mobbdev 1.0.65 → 1.0.74
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 +1559 -1473
- package/package.json +13 -13
package/dist/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ var __export = (target, all) => {
|
|
|
7
7
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
8
8
|
|
|
9
9
|
// src/index.ts
|
|
10
|
-
import
|
|
10
|
+
import Debug20 from "debug";
|
|
11
11
|
import { hideBin } from "yargs/helpers";
|
|
12
12
|
|
|
13
13
|
// src/types.ts
|
|
@@ -111,6 +111,7 @@ var IssueLanguage_Enum = /* @__PURE__ */ ((IssueLanguage_Enum2) => {
|
|
|
111
111
|
})(IssueLanguage_Enum || {});
|
|
112
112
|
var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
|
|
113
113
|
IssueType_Enum2["AutoEscapeFalse"] = "AUTO_ESCAPE_FALSE";
|
|
114
|
+
IssueType_Enum2["AvoidIdentityComparisonCachedTypes"] = "AVOID_IDENTITY_COMPARISON_CACHED_TYPES";
|
|
114
115
|
IssueType_Enum2["ClientDomStoredCodeInjection"] = "CLIENT_DOM_STORED_CODE_INJECTION";
|
|
115
116
|
IssueType_Enum2["CmDi"] = "CMDi";
|
|
116
117
|
IssueType_Enum2["CmDiRelativePathCommand"] = "CMDi_relative_path_command";
|
|
@@ -146,6 +147,7 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
|
|
|
146
147
|
IssueType_Enum2["InsecureBinderConfiguration"] = "INSECURE_BINDER_CONFIGURATION";
|
|
147
148
|
IssueType_Enum2["InsecureCookie"] = "INSECURE_COOKIE";
|
|
148
149
|
IssueType_Enum2["InsecureRandomness"] = "INSECURE_RANDOMNESS";
|
|
150
|
+
IssueType_Enum2["InsecureTmpFile"] = "INSECURE_TMP_FILE";
|
|
149
151
|
IssueType_Enum2["InsecureUuidVersion"] = "INSECURE_UUID_VERSION";
|
|
150
152
|
IssueType_Enum2["InsufficientLogging"] = "INSUFFICIENT_LOGGING";
|
|
151
153
|
IssueType_Enum2["JqueryDeprecatedSymbols"] = "JQUERY_DEPRECATED_SYMBOLS";
|
|
@@ -158,10 +160,13 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
|
|
|
158
160
|
IssueType_Enum2["MissingEqualsOrHashcode"] = "MISSING_EQUALS_OR_HASHCODE";
|
|
159
161
|
IssueType_Enum2["MissingHstsHeader"] = "MISSING_HSTS_HEADER";
|
|
160
162
|
IssueType_Enum2["MissingSslMinversion"] = "MISSING_SSL_MINVERSION";
|
|
163
|
+
IssueType_Enum2["ModifiedDefaultParam"] = "MODIFIED_DEFAULT_PARAM";
|
|
161
164
|
IssueType_Enum2["NonFinalPublicStaticField"] = "NON_FINAL_PUBLIC_STATIC_FIELD";
|
|
162
165
|
IssueType_Enum2["NonReadonlyField"] = "NON_READONLY_FIELD";
|
|
163
166
|
IssueType_Enum2["NoEquivalenceMethod"] = "NO_EQUIVALENCE_METHOD";
|
|
164
167
|
IssueType_Enum2["NoLimitsOrThrottling"] = "NO_LIMITS_OR_THROTTLING";
|
|
168
|
+
IssueType_Enum2["NoReturnInFinally"] = "NO_RETURN_IN_FINALLY";
|
|
169
|
+
IssueType_Enum2["NoVar"] = "NO_VAR";
|
|
165
170
|
IssueType_Enum2["NullDereference"] = "NULL_DEREFERENCE";
|
|
166
171
|
IssueType_Enum2["OpenRedirect"] = "OPEN_REDIRECT";
|
|
167
172
|
IssueType_Enum2["OverlyBroadCatch"] = "OVERLY_BROAD_CATCH";
|
|
@@ -177,6 +182,7 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
|
|
|
177
182
|
IssueType_Enum2["SqlInjection"] = "SQL_Injection";
|
|
178
183
|
IssueType_Enum2["Ssrf"] = "SSRF";
|
|
179
184
|
IssueType_Enum2["StringFormatMisuse"] = "STRING_FORMAT_MISUSE";
|
|
185
|
+
IssueType_Enum2["SystemExitShouldReraise"] = "SYSTEM_EXIT_SHOULD_RERAISE";
|
|
180
186
|
IssueType_Enum2["SystemInformationLeak"] = "SYSTEM_INFORMATION_LEAK";
|
|
181
187
|
IssueType_Enum2["SystemInformationLeakExternal"] = "SYSTEM_INFORMATION_LEAK_EXTERNAL";
|
|
182
188
|
IssueType_Enum2["TrustBoundaryViolation"] = "TRUST_BOUNDARY_VIOLATION";
|
|
@@ -184,6 +190,7 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
|
|
|
184
190
|
IssueType_Enum2["UncheckedLoopCondition"] = "UNCHECKED_LOOP_CONDITION";
|
|
185
191
|
IssueType_Enum2["UnsafeDeserialization"] = "UNSAFE_DESERIALIZATION";
|
|
186
192
|
IssueType_Enum2["UnsafeTargetBlank"] = "UNSAFE_TARGET_BLANK";
|
|
193
|
+
IssueType_Enum2["UnsafeWebThread"] = "UNSAFE_WEB_THREAD";
|
|
187
194
|
IssueType_Enum2["UnvalidatedPublicMethodArgument"] = "UNVALIDATED_PUBLIC_METHOD_ARGUMENT";
|
|
188
195
|
IssueType_Enum2["UselessRegexpCharEscape"] = "USELESS_REGEXP_CHAR_ESCAPE";
|
|
189
196
|
IssueType_Enum2["UseOfHardCodedCryptographicKey"] = "USE_OF_HARD_CODED_CRYPTOGRAPHIC_KEY";
|
|
@@ -458,10 +465,24 @@ var GetVulByNodesMetadataDocument = `
|
|
|
458
465
|
vulnerabilityReportIssueTags {
|
|
459
466
|
tag: vulnerability_report_issue_tag_value
|
|
460
467
|
}
|
|
461
|
-
codeNodes(order_by: {index: desc}, where: {_or: $filters}) {
|
|
468
|
+
codeNodes(order_by: {index: desc}, where: {_or: $filters}, limit: 1) {
|
|
462
469
|
path
|
|
463
470
|
startLine
|
|
464
471
|
}
|
|
472
|
+
fpId
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
`;
|
|
477
|
+
var GetFalsePositiveDocument = `
|
|
478
|
+
query getFalsePositive($fpId: uuid!) {
|
|
479
|
+
getFalsePositive(fpId: $fpId) {
|
|
480
|
+
... on FalsePositiveData {
|
|
481
|
+
extraContext {
|
|
482
|
+
key
|
|
483
|
+
value
|
|
484
|
+
}
|
|
485
|
+
fixDescription
|
|
465
486
|
}
|
|
466
487
|
}
|
|
467
488
|
}
|
|
@@ -692,6 +713,9 @@ function getSdk(client, withWrapper = defaultWrapper) {
|
|
|
692
713
|
getVulByNodesMetadata(variables, requestHeaders) {
|
|
693
714
|
return withWrapper((wrappedRequestHeaders) => client.request(GetVulByNodesMetadataDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getVulByNodesMetadata", "query", variables);
|
|
694
715
|
},
|
|
716
|
+
getFalsePositive(variables, requestHeaders) {
|
|
717
|
+
return withWrapper((wrappedRequestHeaders) => client.request(GetFalsePositiveDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getFalsePositive", "query", variables);
|
|
718
|
+
},
|
|
695
719
|
updateScmToken(variables, requestHeaders) {
|
|
696
720
|
return withWrapper((wrappedRequestHeaders) => client.request(UpdateScmTokenDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "updateScmToken", "mutation", variables);
|
|
697
721
|
},
|
|
@@ -1144,7 +1168,14 @@ var issueTypeMap = {
|
|
|
1144
1168
|
["WEBSOCKET_MISSING_ORIGIN_CHECK" /* WebsocketMissingOriginCheck */]: "Missing Websocket Origin Check",
|
|
1145
1169
|
["DUPLICATED_STRINGS" /* DuplicatedStrings */]: "String Literals Should not Be Duplicated",
|
|
1146
1170
|
["INSECURE_UUID_VERSION" /* InsecureUuidVersion */]: "Insecure UUID Version",
|
|
1147
|
-
["GH_ACTIONS_SHELL_INJECTION" /* GhActionsShellInjection */]: "GitHub Actions Shell Injection"
|
|
1171
|
+
["GH_ACTIONS_SHELL_INJECTION" /* GhActionsShellInjection */]: "GitHub Actions Shell Injection",
|
|
1172
|
+
["MODIFIED_DEFAULT_PARAM" /* ModifiedDefaultParam */]: "Modified Default Param",
|
|
1173
|
+
["UNSAFE_WEB_THREAD" /* UnsafeWebThread */]: "Unsafe Web Thread",
|
|
1174
|
+
["NO_VAR" /* NoVar */]: 'Prefer "let" or "const"',
|
|
1175
|
+
["INSECURE_TMP_FILE" /* InsecureTmpFile */]: "Insecure Temporary File",
|
|
1176
|
+
["SYSTEM_EXIT_SHOULD_RERAISE" /* SystemExitShouldReraise */]: "SystemExit Should Reraise",
|
|
1177
|
+
["NO_RETURN_IN_FINALLY" /* NoReturnInFinally */]: "No Return in Finally Block",
|
|
1178
|
+
["AVOID_IDENTITY_COMPARISON_CACHED_TYPES" /* AvoidIdentityComparisonCachedTypes */]: "Avoid Identity Comparison of Cached Types"
|
|
1148
1179
|
};
|
|
1149
1180
|
var issueTypeZ = z5.nativeEnum(IssueType_Enum);
|
|
1150
1181
|
var getIssueTypeFriendlyString = (issueType) => {
|
|
@@ -1177,6 +1208,22 @@ var issueDescription = {
|
|
|
1177
1208
|
["TEST_CODE" /* TestCode */]: "The flagged code resides in a test-specific path or context. This categorization indicates that **it supports testing scenarios and is isolated from production use**.",
|
|
1178
1209
|
["VENDOR_CODE" /* VendorCode */]: "The flagged code originates from a third-party library or dependency maintained externally. This categorization suggests that **the issue lies outside the application\u2019s direct control** and should be addressed by the vendor if necessary."
|
|
1179
1210
|
};
|
|
1211
|
+
function replaceKeysWithValues(fixDescription, extraContext) {
|
|
1212
|
+
let result = fixDescription;
|
|
1213
|
+
extraContext.forEach(({ key, value }) => {
|
|
1214
|
+
result = result.replace(`\${${key}}`, value);
|
|
1215
|
+
});
|
|
1216
|
+
return result;
|
|
1217
|
+
}
|
|
1218
|
+
function getParsedFalsePositiveMessage(data) {
|
|
1219
|
+
const { fixDescription, extraContext } = data;
|
|
1220
|
+
const containsTemplate = extraContext.some(
|
|
1221
|
+
(context) => fixDescription.includes(`\${${context.key}}`)
|
|
1222
|
+
);
|
|
1223
|
+
const description = containsTemplate ? replaceKeysWithValues(fixDescription, extraContext) : fixDescription;
|
|
1224
|
+
const contextString = containsTemplate ? null : `\`\`\`${extraContext.map(({ value }) => value).join(" ")} \`\`\``;
|
|
1225
|
+
return { description, contextString };
|
|
1226
|
+
}
|
|
1180
1227
|
|
|
1181
1228
|
// src/features/analysis/scm/shared/src/validations.ts
|
|
1182
1229
|
var IssueTypeSettingZ = z6.object({
|
|
@@ -1258,7 +1305,9 @@ var ReportQueryResultZ = z7.object({
|
|
|
1258
1305
|
}),
|
|
1259
1306
|
fixesDoneCount: z7.number(),
|
|
1260
1307
|
fixesInprogressCount: z7.number(),
|
|
1261
|
-
fixesReadyCount: z7.
|
|
1308
|
+
fixesReadyCount: z7.object({
|
|
1309
|
+
aggregate: z7.object({ count: z7.number() })
|
|
1310
|
+
}),
|
|
1262
1311
|
issueTypes: z7.record(z7.string(), z7.number()).nullable(),
|
|
1263
1312
|
issueLanguages: z7.record(z7.string(), z7.number()).nullable(),
|
|
1264
1313
|
fixesCountByEffort: z7.record(z7.string(), z7.number()).nullable(),
|
|
@@ -1786,7 +1835,7 @@ var CliError = class extends Error {
|
|
|
1786
1835
|
// src/features/analysis/index.ts
|
|
1787
1836
|
import chalk4 from "chalk";
|
|
1788
1837
|
import Configstore from "configstore";
|
|
1789
|
-
import
|
|
1838
|
+
import Debug18 from "debug";
|
|
1790
1839
|
import extract from "extract-zip";
|
|
1791
1840
|
import { createSpinner as createSpinner4 } from "nanospinner";
|
|
1792
1841
|
import fetch4 from "node-fetch";
|
|
@@ -1797,9 +1846,6 @@ import { z as z29 } from "zod";
|
|
|
1797
1846
|
// src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
|
|
1798
1847
|
import Debug8 from "debug";
|
|
1799
1848
|
|
|
1800
|
-
// src/features/analysis/scm/github/GithubSCMLib.ts
|
|
1801
|
-
import { z as z24 } from "zod";
|
|
1802
|
-
|
|
1803
1849
|
// src/features/analysis/scm/errors.ts
|
|
1804
1850
|
var InvalidRepoUrlError = class extends Error {
|
|
1805
1851
|
constructor(m) {
|
|
@@ -1828,26 +1874,26 @@ var RepoNoTokenAccessError = class extends Error {
|
|
|
1828
1874
|
}
|
|
1829
1875
|
};
|
|
1830
1876
|
|
|
1831
|
-
// src/features/analysis/scm/
|
|
1832
|
-
|
|
1833
|
-
var isValidBranchName = async (branchName) => {
|
|
1834
|
-
const git = simpleGit();
|
|
1835
|
-
try {
|
|
1836
|
-
const res = await git.raw(["check-ref-format", "--branch", branchName]);
|
|
1837
|
-
if (res) {
|
|
1838
|
-
return true;
|
|
1839
|
-
}
|
|
1840
|
-
return false;
|
|
1841
|
-
} catch (e) {
|
|
1842
|
-
return false;
|
|
1843
|
-
}
|
|
1844
|
-
};
|
|
1877
|
+
// src/features/analysis/scm/ado/constants.ts
|
|
1878
|
+
var DEFUALT_ADO_ORIGIN = scmCloudUrl.Ado;
|
|
1845
1879
|
|
|
1846
|
-
// src/features/analysis/scm/
|
|
1847
|
-
import
|
|
1880
|
+
// src/features/analysis/scm/ado/utils.ts
|
|
1881
|
+
import querystring from "node:querystring";
|
|
1882
|
+
import * as api from "azure-devops-node-api";
|
|
1883
|
+
import Debug2 from "debug";
|
|
1884
|
+
import { z as z18 } from "zod";
|
|
1848
1885
|
|
|
1849
|
-
// src/features/analysis/scm/
|
|
1886
|
+
// src/features/analysis/scm/env.ts
|
|
1850
1887
|
import { z as z9 } from "zod";
|
|
1888
|
+
var EnvVariablesZod = z9.object({
|
|
1889
|
+
GITLAB_API_TOKEN: z9.string().optional(),
|
|
1890
|
+
GITHUB_API_TOKEN: z9.string().optional(),
|
|
1891
|
+
GIT_PROXY_HOST: z9.string()
|
|
1892
|
+
});
|
|
1893
|
+
var { GITLAB_API_TOKEN, GITHUB_API_TOKEN, GIT_PROXY_HOST } = EnvVariablesZod.parse(process.env);
|
|
1894
|
+
|
|
1895
|
+
// src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
|
|
1896
|
+
import { z as z10 } from "zod";
|
|
1851
1897
|
|
|
1852
1898
|
// src/features/analysis/scm/shared/src/fixDetailsData.ts
|
|
1853
1899
|
var fixDetailsData = {
|
|
@@ -2091,7 +2137,14 @@ var fixDetailsData = {
|
|
|
2091
2137
|
["WEBSOCKET_MISSING_ORIGIN_CHECK" /* WebsocketMissingOriginCheck */]: void 0,
|
|
2092
2138
|
["DUPLICATED_STRINGS" /* DuplicatedStrings */]: void 0,
|
|
2093
2139
|
["INSECURE_UUID_VERSION" /* InsecureUuidVersion */]: void 0,
|
|
2094
|
-
["GH_ACTIONS_SHELL_INJECTION" /* GhActionsShellInjection */]: void 0
|
|
2140
|
+
["GH_ACTIONS_SHELL_INJECTION" /* GhActionsShellInjection */]: void 0,
|
|
2141
|
+
["MODIFIED_DEFAULT_PARAM" /* ModifiedDefaultParam */]: void 0,
|
|
2142
|
+
["UNSAFE_WEB_THREAD" /* UnsafeWebThread */]: void 0,
|
|
2143
|
+
["NO_VAR" /* NoVar */]: void 0,
|
|
2144
|
+
["INSECURE_TMP_FILE" /* InsecureTmpFile */]: void 0,
|
|
2145
|
+
["SYSTEM_EXIT_SHOULD_RERAISE" /* SystemExitShouldReraise */]: void 0,
|
|
2146
|
+
["NO_RETURN_IN_FINALLY" /* NoReturnInFinally */]: void 0,
|
|
2147
|
+
["AVOID_IDENTITY_COMPARISON_CACHED_TYPES" /* AvoidIdentityComparisonCachedTypes */]: void 0
|
|
2095
2148
|
};
|
|
2096
2149
|
|
|
2097
2150
|
// src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
|
|
@@ -2122,7 +2175,7 @@ var getCommitDescription = ({
|
|
|
2122
2175
|
)}**.
|
|
2123
2176
|
|
|
2124
2177
|
`;
|
|
2125
|
-
const parseIssueTypeRes =
|
|
2178
|
+
const parseIssueTypeRes = z10.nativeEnum(IssueType_Enum).safeParse(issueType);
|
|
2126
2179
|
if (issueType && parseIssueTypeRes.success) {
|
|
2127
2180
|
if (irrelevantIssueWithTags?.[0]?.tag) {
|
|
2128
2181
|
description += `
|
|
@@ -2159,22 +2212,24 @@ ${guidances.map(({ guidance }) => `## Additional actions required
|
|
|
2159
2212
|
var getCommitIssueDescription = ({
|
|
2160
2213
|
vendor,
|
|
2161
2214
|
issueType,
|
|
2162
|
-
irrelevantIssueWithTags
|
|
2215
|
+
irrelevantIssueWithTags,
|
|
2216
|
+
fpDescription
|
|
2163
2217
|
}) => {
|
|
2164
2218
|
const issueTypeString = getIssueTypeFriendlyString(issueType);
|
|
2165
2219
|
let description = `The following issues reported by ${capitalizeFirstLetter(vendor)} on this PR were found to be irrelevant to your project:
|
|
2166
2220
|
`;
|
|
2167
|
-
const parseIssueTypeRes =
|
|
2221
|
+
const parseIssueTypeRes = z10.nativeEnum(IssueType_Enum).safeParse(issueType);
|
|
2168
2222
|
if (issueType && parseIssueTypeRes.success) {
|
|
2169
2223
|
if (irrelevantIssueWithTags?.[0]?.tag) {
|
|
2170
|
-
description
|
|
2224
|
+
description = `
|
|
2171
2225
|
> [!tip]
|
|
2226
|
+
> The following issues reported by ${capitalizeFirstLetter(vendor)} on this PR were found to be irrelevant to your project:
|
|
2172
2227
|
> ${issueTypeString} - ${lowercaseFirstLetter(getTagTooltip(irrelevantIssueWithTags[0].tag))}.
|
|
2173
2228
|
> Mobb recommends to ignore this issue, however fix is available if you think differently.
|
|
2174
2229
|
|
|
2175
2230
|
|
|
2176
2231
|
## Justification
|
|
2177
|
-
${issueDescription[irrelevantIssueWithTags[0].tag]}
|
|
2232
|
+
${fpDescription ?? issueDescription[irrelevantIssueWithTags[0].tag]}
|
|
2178
2233
|
`;
|
|
2179
2234
|
}
|
|
2180
2235
|
const staticData = fixDetailsData[parseIssueTypeRes.data];
|
|
@@ -2188,10 +2243,10 @@ ${staticData.issueDescription}
|
|
|
2188
2243
|
};
|
|
2189
2244
|
|
|
2190
2245
|
// src/features/analysis/scm/shared/src/guidances.ts
|
|
2191
|
-
import { z as
|
|
2246
|
+
import { z as z13 } from "zod";
|
|
2192
2247
|
|
|
2193
2248
|
// src/features/analysis/scm/shared/src/storedFixData/index.ts
|
|
2194
|
-
import { z as
|
|
2249
|
+
import { z as z11 } from "zod";
|
|
2195
2250
|
|
|
2196
2251
|
// src/features/analysis/scm/shared/src/storedFixData/passwordInComment.ts
|
|
2197
2252
|
var passwordInComment = {
|
|
@@ -2367,8 +2422,8 @@ var vulnerabilities8 = {
|
|
|
2367
2422
|
var xml_default = vulnerabilities8;
|
|
2368
2423
|
|
|
2369
2424
|
// src/features/analysis/scm/shared/src/storedFixData/index.ts
|
|
2370
|
-
var StoredFixDataItemZ =
|
|
2371
|
-
guidance:
|
|
2425
|
+
var StoredFixDataItemZ = z11.object({
|
|
2426
|
+
guidance: z11.function().returns(z11.string())
|
|
2372
2427
|
});
|
|
2373
2428
|
var languages = {
|
|
2374
2429
|
["Java" /* Java */]: java_default,
|
|
@@ -2382,7 +2437,7 @@ var languages = {
|
|
|
2382
2437
|
};
|
|
2383
2438
|
|
|
2384
2439
|
// src/features/analysis/scm/shared/src/storedQuestionData/index.ts
|
|
2385
|
-
import { z as
|
|
2440
|
+
import { z as z12 } from "zod";
|
|
2386
2441
|
|
|
2387
2442
|
// src/features/analysis/scm/shared/src/storedQuestionData/csharp/httpOnlyCookie.ts
|
|
2388
2443
|
var httpOnlyCookie = {
|
|
@@ -3581,10 +3636,10 @@ var vulnerabilities14 = {
|
|
|
3581
3636
|
var xml_default2 = vulnerabilities14;
|
|
3582
3637
|
|
|
3583
3638
|
// src/features/analysis/scm/shared/src/storedQuestionData/index.ts
|
|
3584
|
-
var StoredQuestionDataItemZ =
|
|
3585
|
-
content:
|
|
3586
|
-
description:
|
|
3587
|
-
guidance:
|
|
3639
|
+
var StoredQuestionDataItemZ = z12.object({
|
|
3640
|
+
content: z12.function().args(z12.any()).returns(z12.string()),
|
|
3641
|
+
description: z12.function().args(z12.any()).returns(z12.string()),
|
|
3642
|
+
guidance: z12.function().args(z12.any()).returns(z12.string())
|
|
3588
3643
|
});
|
|
3589
3644
|
var languages2 = {
|
|
3590
3645
|
["Java" /* Java */]: java_default2,
|
|
@@ -3679,9 +3734,9 @@ function getFixGuidances({
|
|
|
3679
3734
|
const fixGuidance = storeFixResult.success ? [storeFixResult.data.guidance({ questions, ...extraContext })] : [];
|
|
3680
3735
|
return libGuidances.concat(fixGuidance).filter((guidance) => !!guidance);
|
|
3681
3736
|
}
|
|
3682
|
-
var IssueTypeAndLanguageZ =
|
|
3683
|
-
issueType:
|
|
3684
|
-
issueLanguage:
|
|
3737
|
+
var IssueTypeAndLanguageZ = z13.object({
|
|
3738
|
+
issueType: z13.nativeEnum(IssueType_Enum),
|
|
3739
|
+
issueLanguage: z13.nativeEnum(IssueLanguage_Enum)
|
|
3685
3740
|
});
|
|
3686
3741
|
function getGuidances(args) {
|
|
3687
3742
|
const safeIssueTypeAndLanguage = IssueTypeAndLanguageZ.safeParse({
|
|
@@ -3719,7 +3774,7 @@ function getGuidances(args) {
|
|
|
3719
3774
|
}
|
|
3720
3775
|
|
|
3721
3776
|
// src/features/analysis/scm/shared/src/urlParser/urlParser.ts
|
|
3722
|
-
import { z as
|
|
3777
|
+
import { z as z14 } from "zod";
|
|
3723
3778
|
var ADO_PREFIX_PATH = "tfs";
|
|
3724
3779
|
var NAME_REGEX = /[a-z0-9\-_.+]+/i;
|
|
3725
3780
|
function detectAdoUrl(args) {
|
|
@@ -3736,7 +3791,7 @@ function detectAdoUrl(args) {
|
|
|
3736
3791
|
scmType: "Ado" /* Ado */,
|
|
3737
3792
|
organization,
|
|
3738
3793
|
// project has single repo - repoName === projectName
|
|
3739
|
-
projectName:
|
|
3794
|
+
projectName: z14.string().parse(projectName),
|
|
3740
3795
|
repoName: projectName,
|
|
3741
3796
|
prefixPath
|
|
3742
3797
|
};
|
|
@@ -3747,7 +3802,7 @@ function detectAdoUrl(args) {
|
|
|
3747
3802
|
return {
|
|
3748
3803
|
scmType: "Ado" /* Ado */,
|
|
3749
3804
|
organization,
|
|
3750
|
-
projectName:
|
|
3805
|
+
projectName: z14.string().parse(projectName),
|
|
3751
3806
|
repoName,
|
|
3752
3807
|
prefixPath
|
|
3753
3808
|
};
|
|
@@ -3761,7 +3816,7 @@ function detectAdoUrl(args) {
|
|
|
3761
3816
|
scmType: "Ado" /* Ado */,
|
|
3762
3817
|
organization,
|
|
3763
3818
|
// project has only one repo - repoName === projectName
|
|
3764
|
-
projectName:
|
|
3819
|
+
projectName: z14.string().parse(repoName),
|
|
3765
3820
|
repoName,
|
|
3766
3821
|
prefixPath
|
|
3767
3822
|
};
|
|
@@ -3771,7 +3826,7 @@ function detectAdoUrl(args) {
|
|
|
3771
3826
|
return {
|
|
3772
3827
|
scmType: "Ado" /* Ado */,
|
|
3773
3828
|
organization,
|
|
3774
|
-
projectName:
|
|
3829
|
+
projectName: z14.string().parse(projectName),
|
|
3775
3830
|
repoName,
|
|
3776
3831
|
prefixPath
|
|
3777
3832
|
};
|
|
@@ -3897,7 +3952,11 @@ function getIssueUrl({
|
|
|
3897
3952
|
return `${appBaseUrl}/organization/${organizationId}/project/${projectId}/report/${analysisId}/issue/${issueId}`;
|
|
3898
3953
|
}
|
|
3899
3954
|
|
|
3955
|
+
// src/features/analysis/scm/utils/index.ts
|
|
3956
|
+
import { z as z16 } from "zod";
|
|
3957
|
+
|
|
3900
3958
|
// src/features/analysis/scm/types.ts
|
|
3959
|
+
import { z as z15 } from "zod";
|
|
3901
3960
|
var ReferenceType = /* @__PURE__ */ ((ReferenceType2) => {
|
|
3902
3961
|
ReferenceType2["BRANCH"] = "BRANCH";
|
|
3903
3962
|
ReferenceType2["COMMIT"] = "COMMIT";
|
|
@@ -3929,14 +3988,13 @@ var scmTypeToScmLibScmType = {
|
|
|
3929
3988
|
["Ado" /* Ado */]: "ADO" /* ADO */,
|
|
3930
3989
|
["Bitbucket" /* Bitbucket */]: "BITBUCKET" /* BITBUCKET */
|
|
3931
3990
|
};
|
|
3932
|
-
var GetRefererenceResultZ =
|
|
3933
|
-
date:
|
|
3934
|
-
sha:
|
|
3935
|
-
type:
|
|
3991
|
+
var GetRefererenceResultZ = z15.object({
|
|
3992
|
+
date: z15.date().optional(),
|
|
3993
|
+
sha: z15.string(),
|
|
3994
|
+
type: z15.nativeEnum(ReferenceType)
|
|
3936
3995
|
});
|
|
3937
3996
|
|
|
3938
3997
|
// src/features/analysis/scm/utils/index.ts
|
|
3939
|
-
import { z as z15 } from "zod";
|
|
3940
3998
|
function getFixUrlWithRedirect(params) {
|
|
3941
3999
|
const {
|
|
3942
4000
|
fixId,
|
|
@@ -4047,7 +4105,7 @@ function shouldValidateUrl(repoUrl) {
|
|
|
4047
4105
|
return repoUrl && isUrlHasPath(repoUrl);
|
|
4048
4106
|
}
|
|
4049
4107
|
function isBrokerUrl(url) {
|
|
4050
|
-
return
|
|
4108
|
+
return z16.string().uuid().safeParse(new URL(url).host).success;
|
|
4051
4109
|
}
|
|
4052
4110
|
function buildAuthorizedRepoUrl(args) {
|
|
4053
4111
|
const { url, username, password } = args;
|
|
@@ -4083,7 +4141,7 @@ function getCloudScmLibTypeFromUrl(url) {
|
|
|
4083
4141
|
return void 0;
|
|
4084
4142
|
}
|
|
4085
4143
|
function getScmLibTypeFromScmType(scmType) {
|
|
4086
|
-
const parsedScmType =
|
|
4144
|
+
const parsedScmType = z16.nativeEnum(ScmType).parse(scmType);
|
|
4087
4145
|
return scmTypeToScmLibScmType[parsedScmType];
|
|
4088
4146
|
}
|
|
4089
4147
|
function getScmConfig({
|
|
@@ -4149,162 +4207,6 @@ function getScmConfig({
|
|
|
4149
4207
|
};
|
|
4150
4208
|
}
|
|
4151
4209
|
|
|
4152
|
-
// src/features/analysis/scm/scm.ts
|
|
4153
|
-
var SCMLib = class {
|
|
4154
|
-
constructor(url, accessToken, scmOrg) {
|
|
4155
|
-
__publicField(this, "url");
|
|
4156
|
-
__publicField(this, "accessToken");
|
|
4157
|
-
__publicField(this, "scmOrg");
|
|
4158
|
-
this.accessToken = accessToken;
|
|
4159
|
-
this.url = url;
|
|
4160
|
-
this.scmOrg = scmOrg;
|
|
4161
|
-
}
|
|
4162
|
-
async getUrlWithCredentials() {
|
|
4163
|
-
if (!this.url) {
|
|
4164
|
-
console.error("no url for getUrlWithCredentials()");
|
|
4165
|
-
throw new Error("no url");
|
|
4166
|
-
}
|
|
4167
|
-
const trimmedUrl = this.url.trim().replace(/\/$/, "");
|
|
4168
|
-
const accessToken = this.getAccessToken();
|
|
4169
|
-
if (!accessToken) {
|
|
4170
|
-
return trimmedUrl;
|
|
4171
|
-
}
|
|
4172
|
-
if (this.scmLibType === "ADO" /* ADO */) {
|
|
4173
|
-
const { host, protocol, pathname } = new URL(trimmedUrl);
|
|
4174
|
-
return `${protocol}//${accessToken}@${host}${pathname}`;
|
|
4175
|
-
}
|
|
4176
|
-
const finalUrl = this.scmLibType === "GITLAB" /* GITLAB */ ? `${trimmedUrl}.git` : trimmedUrl;
|
|
4177
|
-
const username = await this._getUsernameForAuthUrl();
|
|
4178
|
-
return buildAuthorizedRepoUrl({
|
|
4179
|
-
url: finalUrl,
|
|
4180
|
-
username,
|
|
4181
|
-
password: accessToken
|
|
4182
|
-
});
|
|
4183
|
-
}
|
|
4184
|
-
getAccessToken() {
|
|
4185
|
-
return this.accessToken || "";
|
|
4186
|
-
}
|
|
4187
|
-
getUrl() {
|
|
4188
|
-
return this.url;
|
|
4189
|
-
}
|
|
4190
|
-
getName() {
|
|
4191
|
-
if (!this.url) {
|
|
4192
|
-
return "";
|
|
4193
|
-
}
|
|
4194
|
-
return this.url.split("/").at(-1) || "";
|
|
4195
|
-
}
|
|
4196
|
-
_validateAccessToken() {
|
|
4197
|
-
if (!this.accessToken) {
|
|
4198
|
-
console.error("no access token");
|
|
4199
|
-
throw new Error("no access token");
|
|
4200
|
-
}
|
|
4201
|
-
}
|
|
4202
|
-
static async getIsValidBranchName(branchName) {
|
|
4203
|
-
return isValidBranchName(branchName);
|
|
4204
|
-
}
|
|
4205
|
-
_validateAccessTokenAndUrl() {
|
|
4206
|
-
this._validateAccessToken();
|
|
4207
|
-
this._validateUrl();
|
|
4208
|
-
}
|
|
4209
|
-
_validateUrl() {
|
|
4210
|
-
if (!this.url) {
|
|
4211
|
-
console.error("no url");
|
|
4212
|
-
throw new InvalidRepoUrlError("no url");
|
|
4213
|
-
}
|
|
4214
|
-
}
|
|
4215
|
-
};
|
|
4216
|
-
|
|
4217
|
-
// src/features/analysis/scm/github/github.ts
|
|
4218
|
-
import { RequestError } from "@octokit/request-error";
|
|
4219
|
-
|
|
4220
|
-
// src/features/analysis/scm/constants.ts
|
|
4221
|
-
var MOBB_ICON_IMG = "https://app.mobb.ai/gh-action/Logo_Rounded_Icon.svg";
|
|
4222
|
-
var MAX_BRANCHES_FETCH = 1e3;
|
|
4223
|
-
|
|
4224
|
-
// src/features/analysis/scm/github/consts.ts
|
|
4225
|
-
var POST_COMMENT_PATH = "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments";
|
|
4226
|
-
var DELETE_COMMENT_PATH = "DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}";
|
|
4227
|
-
var UPDATE_COMMENT_PATH = "PATCH /repos/{owner}/{repo}/pulls/comments/{comment_id}";
|
|
4228
|
-
var GET_PR_COMMENTS_PATH = "GET /repos/{owner}/{repo}/pulls/{pull_number}/comments";
|
|
4229
|
-
var GET_PR_COMMENT_PATH = "GET /repos/{owner}/{repo}/pulls/comments/{comment_id}";
|
|
4230
|
-
var REPLY_TO_CODE_REVIEW_COMMENT_PATH = "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies";
|
|
4231
|
-
var GET_PR = "GET /repos/{owner}/{repo}/pulls/{pull_number}";
|
|
4232
|
-
var POST_GENERAL_PR_COMMENT = "POST /repos/{owner}/{repo}/issues/{issue_number}/comments";
|
|
4233
|
-
var GET_GENERAL_PR_COMMENTS = "GET /repos/{owner}/{repo}/issues/{issue_number}/comments";
|
|
4234
|
-
var DELETE_GENERAL_PR_COMMENT = "DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}";
|
|
4235
|
-
var CREATE_OR_UPDATE_A_REPOSITORY_SECRET = "PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}";
|
|
4236
|
-
var GET_A_REPOSITORY_PUBLIC_KEY = "GET /repos/{owner}/{repo}/actions/secrets/public-key";
|
|
4237
|
-
var GET_USER = "GET /user";
|
|
4238
|
-
var GET_USER_REPOS = "GET /user/repos";
|
|
4239
|
-
var GET_REPO_BRANCHES = "GET /repos/{owner}/{repo}/branches";
|
|
4240
|
-
var GET_BLAME_DOCUMENT = `
|
|
4241
|
-
query GetBlame(
|
|
4242
|
-
$owner: String!
|
|
4243
|
-
$repo: String!
|
|
4244
|
-
$ref: String!
|
|
4245
|
-
$path: String!
|
|
4246
|
-
) {
|
|
4247
|
-
repository(name: $repo, owner: $owner) {
|
|
4248
|
-
# branch name
|
|
4249
|
-
object(expression: $ref) {
|
|
4250
|
-
# cast Target to a Commit
|
|
4251
|
-
... on Commit {
|
|
4252
|
-
# full repo-relative path to blame file
|
|
4253
|
-
blame(path: $path) {
|
|
4254
|
-
ranges {
|
|
4255
|
-
commit {
|
|
4256
|
-
author {
|
|
4257
|
-
user {
|
|
4258
|
-
name
|
|
4259
|
-
login
|
|
4260
|
-
}
|
|
4261
|
-
}
|
|
4262
|
-
authoredDate
|
|
4263
|
-
}
|
|
4264
|
-
startingLine
|
|
4265
|
-
endingLine
|
|
4266
|
-
age
|
|
4267
|
-
}
|
|
4268
|
-
}
|
|
4269
|
-
}
|
|
4270
|
-
|
|
4271
|
-
}
|
|
4272
|
-
}
|
|
4273
|
-
}
|
|
4274
|
-
`;
|
|
4275
|
-
|
|
4276
|
-
// src/features/analysis/scm/github/utils/encrypt_secret.ts
|
|
4277
|
-
import sodium from "libsodium-wrappers";
|
|
4278
|
-
async function encryptSecret(secret, key) {
|
|
4279
|
-
await sodium.ready;
|
|
4280
|
-
const binkey = sodium.from_base64(key, sodium.base64_variants.ORIGINAL);
|
|
4281
|
-
const binsec = sodium.from_string(secret);
|
|
4282
|
-
const encBytes = sodium.crypto_box_seal(binsec, binkey);
|
|
4283
|
-
return sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL);
|
|
4284
|
-
}
|
|
4285
|
-
|
|
4286
|
-
// src/features/analysis/scm/github/utils/utils.ts
|
|
4287
|
-
import { Octokit } from "octokit";
|
|
4288
|
-
import { fetch as fetch2, ProxyAgent as ProxyAgent2 } from "undici";
|
|
4289
|
-
|
|
4290
|
-
// src/features/analysis/scm/ado/constants.ts
|
|
4291
|
-
var DEFUALT_ADO_ORIGIN = scmCloudUrl.Ado;
|
|
4292
|
-
|
|
4293
|
-
// src/features/analysis/scm/ado/utils.ts
|
|
4294
|
-
import querystring from "node:querystring";
|
|
4295
|
-
import * as api from "azure-devops-node-api";
|
|
4296
|
-
import Debug2 from "debug";
|
|
4297
|
-
import { z as z18 } from "zod";
|
|
4298
|
-
|
|
4299
|
-
// src/features/analysis/scm/env.ts
|
|
4300
|
-
import { z as z16 } from "zod";
|
|
4301
|
-
var EnvVariablesZod = z16.object({
|
|
4302
|
-
GITLAB_API_TOKEN: z16.string().optional(),
|
|
4303
|
-
GITHUB_API_TOKEN: z16.string().optional(),
|
|
4304
|
-
GIT_PROXY_HOST: z16.string()
|
|
4305
|
-
});
|
|
4306
|
-
var { GITLAB_API_TOKEN, GITHUB_API_TOKEN, GIT_PROXY_HOST } = EnvVariablesZod.parse(process.env);
|
|
4307
|
-
|
|
4308
4210
|
// src/features/analysis/scm/ado/validation.ts
|
|
4309
4211
|
import { z as z17 } from "zod";
|
|
4310
4212
|
var ValidPullRequestStatusZ = z17.union([
|
|
@@ -4915,36 +4817,118 @@ async function getAdoRepoList({
|
|
|
4915
4817
|
|
|
4916
4818
|
// src/features/analysis/scm/ado/AdoSCMLib.ts
|
|
4917
4819
|
import { setTimeout as setTimeout2 } from "node:timers/promises";
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
var AdoSCMLib = class extends SCMLib {
|
|
4928
|
-
constructor(url, accessToken, scmOrg) {
|
|
4929
|
-
super(url, accessToken, scmOrg);
|
|
4930
|
-
__publicField(this, "_adoSdkPromise");
|
|
4931
|
-
this._adoSdkPromise = initAdoSdk({ accessToken, url, scmOrg });
|
|
4932
|
-
}
|
|
4933
|
-
async getAdoSdk() {
|
|
4934
|
-
if (!this._adoSdkPromise) {
|
|
4935
|
-
console.error("ado sdk was not initialized");
|
|
4936
|
-
throw new InvalidAccessTokenError("ado sdk was not initialized");
|
|
4820
|
+
|
|
4821
|
+
// src/features/analysis/scm/scmSubmit/index.ts
|
|
4822
|
+
import { simpleGit } from "simple-git";
|
|
4823
|
+
var isValidBranchName = async (branchName) => {
|
|
4824
|
+
const git = simpleGit();
|
|
4825
|
+
try {
|
|
4826
|
+
const res = await git.raw(["check-ref-format", "--branch", branchName]);
|
|
4827
|
+
if (res) {
|
|
4828
|
+
return true;
|
|
4937
4829
|
}
|
|
4938
|
-
return
|
|
4830
|
+
return false;
|
|
4831
|
+
} catch (e) {
|
|
4832
|
+
return false;
|
|
4939
4833
|
}
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4834
|
+
};
|
|
4835
|
+
|
|
4836
|
+
// src/features/analysis/scm/scm.ts
|
|
4837
|
+
var SCMLib = class {
|
|
4838
|
+
constructor(url, accessToken, scmOrg) {
|
|
4839
|
+
__publicField(this, "url");
|
|
4840
|
+
__publicField(this, "accessToken");
|
|
4841
|
+
__publicField(this, "scmOrg");
|
|
4842
|
+
this.accessToken = accessToken;
|
|
4843
|
+
this.url = url;
|
|
4844
|
+
this.scmOrg = scmOrg;
|
|
4845
|
+
}
|
|
4846
|
+
async getUrlWithCredentials() {
|
|
4847
|
+
if (!this.url) {
|
|
4848
|
+
console.error("no url for getUrlWithCredentials()");
|
|
4849
|
+
throw new Error("no url");
|
|
4850
|
+
}
|
|
4851
|
+
const trimmedUrl = this.url.trim().replace(/\/$/, "");
|
|
4852
|
+
const accessToken = this.getAccessToken();
|
|
4853
|
+
if (!accessToken) {
|
|
4854
|
+
return trimmedUrl;
|
|
4855
|
+
}
|
|
4856
|
+
if (this.scmLibType === "ADO" /* ADO */) {
|
|
4857
|
+
const { host, protocol, pathname } = new URL(trimmedUrl);
|
|
4858
|
+
return `${protocol}//${accessToken}@${host}${pathname}`;
|
|
4859
|
+
}
|
|
4860
|
+
const finalUrl = this.scmLibType === "GITLAB" /* GITLAB */ ? `${trimmedUrl}.git` : trimmedUrl;
|
|
4861
|
+
const username = await this._getUsernameForAuthUrl();
|
|
4862
|
+
return buildAuthorizedRepoUrl({
|
|
4863
|
+
url: finalUrl,
|
|
4864
|
+
username,
|
|
4865
|
+
password: accessToken
|
|
4866
|
+
});
|
|
4867
|
+
}
|
|
4868
|
+
getAccessToken() {
|
|
4869
|
+
return this.accessToken || "";
|
|
4870
|
+
}
|
|
4871
|
+
getUrl() {
|
|
4872
|
+
return this.url;
|
|
4873
|
+
}
|
|
4874
|
+
getName() {
|
|
4875
|
+
if (!this.url) {
|
|
4876
|
+
return "";
|
|
4877
|
+
}
|
|
4878
|
+
return this.url.split("/").at(-1) || "";
|
|
4879
|
+
}
|
|
4880
|
+
_validateAccessToken() {
|
|
4881
|
+
if (!this.accessToken) {
|
|
4882
|
+
console.error("no access token");
|
|
4883
|
+
throw new Error("no access token");
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
static async getIsValidBranchName(branchName) {
|
|
4887
|
+
return isValidBranchName(branchName);
|
|
4888
|
+
}
|
|
4889
|
+
_validateAccessTokenAndUrl() {
|
|
4890
|
+
this._validateAccessToken();
|
|
4891
|
+
this._validateUrl();
|
|
4892
|
+
}
|
|
4893
|
+
_validateUrl() {
|
|
4894
|
+
if (!this.url) {
|
|
4895
|
+
console.error("no url");
|
|
4896
|
+
throw new InvalidRepoUrlError("no url");
|
|
4897
|
+
}
|
|
4898
|
+
}
|
|
4899
|
+
};
|
|
4900
|
+
|
|
4901
|
+
// src/features/analysis/scm/ado/AdoSCMLib.ts
|
|
4902
|
+
async function initAdoSdk(params) {
|
|
4903
|
+
const { url, accessToken, scmOrg } = params;
|
|
4904
|
+
const adoClientParams = await getAdoClientParams({
|
|
4905
|
+
tokenOrg: scmOrg,
|
|
4906
|
+
accessToken,
|
|
4907
|
+
url
|
|
4908
|
+
});
|
|
4909
|
+
return getAdoSdk(adoClientParams);
|
|
4910
|
+
}
|
|
4911
|
+
var AdoSCMLib = class extends SCMLib {
|
|
4912
|
+
constructor(url, accessToken, scmOrg) {
|
|
4913
|
+
super(url, accessToken, scmOrg);
|
|
4914
|
+
__publicField(this, "_adoSdkPromise");
|
|
4915
|
+
this._adoSdkPromise = initAdoSdk({ accessToken, url, scmOrg });
|
|
4916
|
+
}
|
|
4917
|
+
async getAdoSdk() {
|
|
4918
|
+
if (!this._adoSdkPromise) {
|
|
4919
|
+
console.error("ado sdk was not initialized");
|
|
4920
|
+
throw new InvalidAccessTokenError("ado sdk was not initialized");
|
|
4921
|
+
}
|
|
4922
|
+
return this._adoSdkPromise;
|
|
4923
|
+
}
|
|
4924
|
+
async createSubmitRequest(params) {
|
|
4925
|
+
this._validateAccessTokenAndUrl();
|
|
4926
|
+
for (let i = 0; i < 5; i++) {
|
|
4927
|
+
try {
|
|
4928
|
+
const { targetBranchName, sourceBranchName, title, body } = params;
|
|
4929
|
+
const adoSdk = await this.getAdoSdk();
|
|
4930
|
+
const pullRequestId = await adoSdk.createAdoPullRequest({
|
|
4931
|
+
title,
|
|
4948
4932
|
body,
|
|
4949
4933
|
targetBranchName,
|
|
4950
4934
|
sourceBranchName,
|
|
@@ -5659,787 +5643,175 @@ var BitbucketSCMLib = class extends SCMLib {
|
|
|
5659
5643
|
}
|
|
5660
5644
|
};
|
|
5661
5645
|
|
|
5662
|
-
// src/features/analysis/scm/
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
createRequesterFn
|
|
5666
|
-
} from "@gitbeaker/requester-utils";
|
|
5667
|
-
import {
|
|
5668
|
-
AccessLevel,
|
|
5669
|
-
Gitlab
|
|
5670
|
-
} from "@gitbeaker/rest";
|
|
5671
|
-
import Debug4 from "debug";
|
|
5672
|
-
import {
|
|
5673
|
-
fetch as undiciFetch,
|
|
5674
|
-
ProxyAgent
|
|
5675
|
-
} from "undici";
|
|
5646
|
+
// src/features/analysis/scm/constants.ts
|
|
5647
|
+
var MOBB_ICON_IMG = "https://app.mobb.ai/gh-action/Logo_Rounded_Icon.svg";
|
|
5648
|
+
var MAX_BRANCHES_FETCH = 1e3;
|
|
5676
5649
|
|
|
5677
|
-
// src/features/analysis/scm/
|
|
5650
|
+
// src/features/analysis/scm/github/GithubSCMLib.ts
|
|
5678
5651
|
import { z as z22 } from "zod";
|
|
5679
|
-
var GitlabAuthResultZ = z22.object({
|
|
5680
|
-
access_token: z22.string(),
|
|
5681
|
-
token_type: z22.string(),
|
|
5682
|
-
refresh_token: z22.string()
|
|
5683
|
-
});
|
|
5684
5652
|
|
|
5685
|
-
// src/features/analysis/scm/
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5653
|
+
// src/features/analysis/scm/github/github.ts
|
|
5654
|
+
import { RequestError } from "@octokit/request-error";
|
|
5655
|
+
|
|
5656
|
+
// src/features/analysis/scm/github/consts.ts
|
|
5657
|
+
var POST_COMMENT_PATH = "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments";
|
|
5658
|
+
var DELETE_COMMENT_PATH = "DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}";
|
|
5659
|
+
var UPDATE_COMMENT_PATH = "PATCH /repos/{owner}/{repo}/pulls/comments/{comment_id}";
|
|
5660
|
+
var GET_PR_COMMENTS_PATH = "GET /repos/{owner}/{repo}/pulls/{pull_number}/comments";
|
|
5661
|
+
var GET_PR_COMMENT_PATH = "GET /repos/{owner}/{repo}/pulls/comments/{comment_id}";
|
|
5662
|
+
var REPLY_TO_CODE_REVIEW_COMMENT_PATH = "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies";
|
|
5663
|
+
var GET_PR = "GET /repos/{owner}/{repo}/pulls/{pull_number}";
|
|
5664
|
+
var POST_GENERAL_PR_COMMENT = "POST /repos/{owner}/{repo}/issues/{issue_number}/comments";
|
|
5665
|
+
var GET_GENERAL_PR_COMMENTS = "GET /repos/{owner}/{repo}/issues/{issue_number}/comments";
|
|
5666
|
+
var DELETE_GENERAL_PR_COMMENT = "DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}";
|
|
5667
|
+
var CREATE_OR_UPDATE_A_REPOSITORY_SECRET = "PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}";
|
|
5668
|
+
var GET_A_REPOSITORY_PUBLIC_KEY = "GET /repos/{owner}/{repo}/actions/secrets/public-key";
|
|
5669
|
+
var GET_USER = "GET /user";
|
|
5670
|
+
var GET_USER_REPOS = "GET /user/repos";
|
|
5671
|
+
var GET_REPO_BRANCHES = "GET /repos/{owner}/{repo}/branches";
|
|
5672
|
+
var GET_BLAME_DOCUMENT = `
|
|
5673
|
+
query GetBlame(
|
|
5674
|
+
$owner: String!
|
|
5675
|
+
$repo: String!
|
|
5676
|
+
$ref: String!
|
|
5677
|
+
$path: String!
|
|
5678
|
+
) {
|
|
5679
|
+
repository(name: $repo, owner: $owner) {
|
|
5680
|
+
# branch name
|
|
5681
|
+
object(expression: $ref) {
|
|
5682
|
+
# cast Target to a Commit
|
|
5683
|
+
... on Commit {
|
|
5684
|
+
# full repo-relative path to blame file
|
|
5685
|
+
blame(path: $path) {
|
|
5686
|
+
ranges {
|
|
5687
|
+
commit {
|
|
5688
|
+
author {
|
|
5689
|
+
user {
|
|
5690
|
+
name
|
|
5691
|
+
login
|
|
5692
|
+
}
|
|
5693
|
+
}
|
|
5694
|
+
authoredDate
|
|
5695
|
+
}
|
|
5696
|
+
startingLine
|
|
5697
|
+
endingLine
|
|
5698
|
+
age
|
|
5699
|
+
}
|
|
5700
|
+
}
|
|
5701
|
+
}
|
|
5702
|
+
|
|
5703
|
+
}
|
|
5704
|
+
}
|
|
5705
|
+
}
|
|
5706
|
+
`;
|
|
5707
|
+
|
|
5708
|
+
// src/features/analysis/scm/github/utils/encrypt_secret.ts
|
|
5709
|
+
import sodium from "libsodium-wrappers";
|
|
5710
|
+
async function encryptSecret(secret, key) {
|
|
5711
|
+
await sodium.ready;
|
|
5712
|
+
const binkey = sodium.from_base64(key, sodium.base64_variants.ORIGINAL);
|
|
5713
|
+
const binsec = sodium.from_string(secret);
|
|
5714
|
+
const encBytes = sodium.crypto_box_seal(binsec, binkey);
|
|
5715
|
+
return sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL);
|
|
5689
5716
|
}
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5717
|
+
|
|
5718
|
+
// src/features/analysis/scm/github/utils/utils.ts
|
|
5719
|
+
import { Octokit } from "octokit";
|
|
5720
|
+
import { fetch as fetch2, ProxyAgent } from "undici";
|
|
5721
|
+
function parseGithubOwnerAndRepo(gitHubUrl) {
|
|
5722
|
+
gitHubUrl = normalizeUrl(gitHubUrl);
|
|
5723
|
+
const parsingResult = parseScmURL(gitHubUrl, "GitHub" /* GitHub */);
|
|
5724
|
+
if (!parsingResult) {
|
|
5725
|
+
throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
|
|
5693
5726
|
}
|
|
5694
|
-
const
|
|
5695
|
-
|
|
5696
|
-
}
|
|
5697
|
-
function getGitBeaker(options) {
|
|
5698
|
-
const token = options?.gitlabAuthToken ?? getRandomGitlabCloudAnonToken() ?? "";
|
|
5699
|
-
const url = options.url;
|
|
5700
|
-
const host = url ? new URL(url).origin : "https://gitlab.com";
|
|
5701
|
-
if (token?.startsWith("glpat-") || token === "") {
|
|
5702
|
-
return new Gitlab({
|
|
5703
|
-
token,
|
|
5704
|
-
host,
|
|
5705
|
-
requesterFn: createRequesterFn(
|
|
5706
|
-
(_, reqo) => Promise.resolve(reqo),
|
|
5707
|
-
brokerRequestHandler
|
|
5708
|
-
)
|
|
5709
|
-
});
|
|
5727
|
+
const { organization, repoName } = parsingResult;
|
|
5728
|
+
if (!organization || !repoName) {
|
|
5729
|
+
throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
|
|
5710
5730
|
}
|
|
5711
|
-
return
|
|
5712
|
-
oauthToken: token,
|
|
5713
|
-
host,
|
|
5714
|
-
requesterFn: createRequesterFn(
|
|
5715
|
-
(_, reqo) => Promise.resolve(reqo),
|
|
5716
|
-
brokerRequestHandler
|
|
5717
|
-
)
|
|
5718
|
-
});
|
|
5731
|
+
return { owner: organization, repo: repoName };
|
|
5719
5732
|
}
|
|
5720
|
-
|
|
5721
|
-
url
|
|
5722
|
-
|
|
5723
|
-
}) {
|
|
5724
|
-
try {
|
|
5725
|
-
const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
|
|
5726
|
-
if (accessToken) {
|
|
5727
|
-
await api2.Users.showCurrentUser();
|
|
5728
|
-
}
|
|
5729
|
-
if (url && shouldValidateUrl(url)) {
|
|
5730
|
-
const { projectPath } = parseGitlabOwnerAndRepo(url);
|
|
5731
|
-
await api2.Projects.show(projectPath);
|
|
5732
|
-
}
|
|
5733
|
-
} catch (e) {
|
|
5734
|
-
const error = e;
|
|
5735
|
-
const code = error.code || error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
|
|
5736
|
-
const description = error.description || `${e}`;
|
|
5737
|
-
if (code === 401 || code === 403 || description.includes("401") || description.includes("403")) {
|
|
5738
|
-
throw new InvalidAccessTokenError(`invalid gitlab access token`);
|
|
5739
|
-
}
|
|
5740
|
-
if (code === 404 || description.includes("404") || description.includes("Not Found")) {
|
|
5741
|
-
throw new InvalidRepoUrlError(`invalid gitlab repo URL: ${url}`);
|
|
5742
|
-
}
|
|
5743
|
-
console.log("gitlabValidateParams error", e);
|
|
5744
|
-
throw new InvalidRepoUrlError(
|
|
5745
|
-
`cannot access gitlab repo URL: ${url} with the provided access token`
|
|
5746
|
-
);
|
|
5733
|
+
function isGithubOnPrem(url) {
|
|
5734
|
+
if (!url) {
|
|
5735
|
+
return false;
|
|
5747
5736
|
}
|
|
5737
|
+
return !url.includes(scmCloudUrl.GitHub);
|
|
5748
5738
|
}
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
const projectAccess = proj.permissions?.project_access?.access_level || 0;
|
|
5764
|
-
const accessLevelWithWriteAccess = [
|
|
5765
|
-
AccessLevel.DEVELOPER,
|
|
5766
|
-
AccessLevel.MAINTAINER,
|
|
5767
|
-
AccessLevel.OWNER,
|
|
5768
|
-
AccessLevel.ADMIN
|
|
5769
|
-
];
|
|
5770
|
-
return accessLevelWithWriteAccess.includes(groupAccess) || accessLevelWithWriteAccess.includes(projectAccess);
|
|
5771
|
-
} catch (e) {
|
|
5772
|
-
return false;
|
|
5773
|
-
}
|
|
5774
|
-
}
|
|
5775
|
-
var gitlabMergeRequestStatus = {
|
|
5776
|
-
merged: "merged",
|
|
5777
|
-
opened: "opened",
|
|
5778
|
-
closed: "closed"
|
|
5779
|
-
};
|
|
5780
|
-
async function getGitlabMergeRequestStatus({
|
|
5781
|
-
accessToken,
|
|
5782
|
-
repoUrl,
|
|
5783
|
-
mrNumber
|
|
5784
|
-
}) {
|
|
5785
|
-
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
5786
|
-
const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
|
|
5787
|
-
const res = await api2.MergeRequests.show(projectPath, mrNumber);
|
|
5788
|
-
switch (res.state) {
|
|
5789
|
-
case gitlabMergeRequestStatus.merged:
|
|
5790
|
-
case gitlabMergeRequestStatus.opened:
|
|
5791
|
-
case gitlabMergeRequestStatus.closed:
|
|
5792
|
-
return res.state;
|
|
5793
|
-
default:
|
|
5794
|
-
throw new Error(`unknown merge request state ${res.state}`);
|
|
5739
|
+
function getFetch(url) {
|
|
5740
|
+
if (url && isBrokerUrl(url)) {
|
|
5741
|
+
const dispatcher = new ProxyAgent({
|
|
5742
|
+
uri: GIT_PROXY_HOST,
|
|
5743
|
+
requestTls: {
|
|
5744
|
+
rejectUnauthorized: false
|
|
5745
|
+
}
|
|
5746
|
+
});
|
|
5747
|
+
return (input, init) => {
|
|
5748
|
+
return fetch2(input, {
|
|
5749
|
+
...init,
|
|
5750
|
+
dispatcher
|
|
5751
|
+
});
|
|
5752
|
+
};
|
|
5795
5753
|
}
|
|
5754
|
+
return fetch2;
|
|
5796
5755
|
}
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
repoUrl,
|
|
5801
|
-
mrNumber
|
|
5802
|
-
}) {
|
|
5803
|
-
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
5804
|
-
const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
|
|
5805
|
-
return api2.MergeRequestNotes.create(projectPath, mrNumber, markdownComment);
|
|
5806
|
-
}
|
|
5807
|
-
async function getGitlabIsRemoteBranch({
|
|
5808
|
-
accessToken,
|
|
5809
|
-
repoUrl,
|
|
5810
|
-
branch
|
|
5811
|
-
}) {
|
|
5812
|
-
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
5813
|
-
const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
|
|
5814
|
-
try {
|
|
5815
|
-
const res = await api2.Branches.show(projectPath, branch);
|
|
5816
|
-
return res.name === branch;
|
|
5817
|
-
} catch (e) {
|
|
5818
|
-
return false;
|
|
5756
|
+
function getRandomGithubCloudAnonToken() {
|
|
5757
|
+
if (!GITHUB_API_TOKEN || typeof GITHUB_API_TOKEN !== "string") {
|
|
5758
|
+
return void 0;
|
|
5819
5759
|
}
|
|
5760
|
+
const tokens = GITHUB_API_TOKEN.split(",");
|
|
5761
|
+
return tokens[Math.floor(Math.random() * tokens.length)];
|
|
5820
5762
|
}
|
|
5821
|
-
|
|
5822
|
-
const
|
|
5823
|
-
const
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
//
|
|
5829
|
-
//
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5763
|
+
function getOctoKit(options) {
|
|
5764
|
+
const token = !options?.auth && !isGithubOnPrem(options?.url) ? getRandomGithubCloudAnonToken() : options?.auth;
|
|
5765
|
+
const baseUrl = options?.url && isGithubOnPrem(options.url) ? `${new URL(options.url).origin}/api/v3` : void 0;
|
|
5766
|
+
return new Octokit({
|
|
5767
|
+
...options,
|
|
5768
|
+
auth: token,
|
|
5769
|
+
baseUrl,
|
|
5770
|
+
//GITHUB_API_TOKEN is only defined in the backend and not when running Bugsy as CLI. We want to enable these debug logs in the backend
|
|
5771
|
+
//to debug the performance of these API calls.
|
|
5772
|
+
log: GITHUB_API_TOKEN ? console : void 0,
|
|
5773
|
+
request: {
|
|
5774
|
+
fetch: getFetch(baseUrl)
|
|
5775
|
+
},
|
|
5776
|
+
retry: {
|
|
5777
|
+
enabled: false
|
|
5778
|
+
},
|
|
5779
|
+
throttle: {
|
|
5780
|
+
enabled: false
|
|
5781
|
+
}
|
|
5833
5782
|
});
|
|
5834
|
-
return Promise.all(
|
|
5835
|
-
res.map(async (project) => {
|
|
5836
|
-
const proj = await api2.Projects.show(project.id);
|
|
5837
|
-
const owner = proj.namespace.name;
|
|
5838
|
-
const repoLanguages = await api2.Projects.showLanguages(project.id);
|
|
5839
|
-
return {
|
|
5840
|
-
repoName: project.path,
|
|
5841
|
-
repoUrl: project.web_url,
|
|
5842
|
-
repoOwner: owner,
|
|
5843
|
-
repoLanguages: Object.keys(repoLanguages),
|
|
5844
|
-
repoIsPublic: project.visibility === "public",
|
|
5845
|
-
repoUpdatedAt: project.last_activity_at
|
|
5846
|
-
};
|
|
5847
|
-
})
|
|
5848
|
-
);
|
|
5849
5783
|
}
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
5855
|
-
const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
|
|
5784
|
+
function isGithubActionActionToken(token) {
|
|
5785
|
+
return token.startsWith("ghs_");
|
|
5786
|
+
}
|
|
5787
|
+
async function githubValidateParams(url, accessToken) {
|
|
5856
5788
|
try {
|
|
5857
|
-
const
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
}
|
|
5868
|
-
|
|
5869
|
-
});
|
|
5870
|
-
return res.map((branch) => branch.name).slice(0, MAX_BRANCHES_FETCH);
|
|
5789
|
+
const oktoKit = getOctoKit({ auth: accessToken, url });
|
|
5790
|
+
if (accessToken && !isGithubActionActionToken(accessToken)) {
|
|
5791
|
+
await oktoKit.rest.users.getAuthenticated();
|
|
5792
|
+
}
|
|
5793
|
+
if (url && shouldValidateUrl(url)) {
|
|
5794
|
+
const { owner, repo } = parseGithubOwnerAndRepo(url);
|
|
5795
|
+
await oktoKit.request(GET_REPO_BRANCHES, {
|
|
5796
|
+
owner,
|
|
5797
|
+
repo,
|
|
5798
|
+
per_page: 1
|
|
5799
|
+
});
|
|
5800
|
+
}
|
|
5871
5801
|
} catch (e) {
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
const api2 = getGitBeaker({
|
|
5878
|
-
url: options.repoUrl,
|
|
5879
|
-
gitlabAuthToken: options.accessToken
|
|
5880
|
-
});
|
|
5881
|
-
const res = await api2.MergeRequests.create(
|
|
5882
|
-
projectPath,
|
|
5883
|
-
options.sourceBranchName,
|
|
5884
|
-
options.targetBranchName,
|
|
5885
|
-
options.title,
|
|
5886
|
-
{
|
|
5887
|
-
description: options.body
|
|
5802
|
+
console.log("could not init github scm", e);
|
|
5803
|
+
const error = e;
|
|
5804
|
+
const code = error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
|
|
5805
|
+
if (code === 401 || code === 403) {
|
|
5806
|
+
throw new InvalidAccessTokenError(`invalid github access token`);
|
|
5888
5807
|
}
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
}
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
}) {
|
|
5897
|
-
const { projectPath } = parseGitlabOwnerAndRepo(url);
|
|
5898
|
-
const api2 = getGitBeaker({
|
|
5899
|
-
url,
|
|
5900
|
-
gitlabAuthToken: accessToken
|
|
5901
|
-
});
|
|
5902
|
-
return await api2.MergeRequests.show(projectPath, prNumber);
|
|
5903
|
-
}
|
|
5904
|
-
async function getGitlabCommitUrl({
|
|
5905
|
-
url,
|
|
5906
|
-
commitSha,
|
|
5907
|
-
accessToken
|
|
5908
|
-
}) {
|
|
5909
|
-
const { projectPath } = parseGitlabOwnerAndRepo(url);
|
|
5910
|
-
const api2 = getGitBeaker({
|
|
5911
|
-
url,
|
|
5912
|
-
gitlabAuthToken: accessToken
|
|
5913
|
-
});
|
|
5914
|
-
return await api2.Commits.show(projectPath, commitSha);
|
|
5915
|
-
}
|
|
5916
|
-
async function getGitlabRepoDefaultBranch(repoUrl, options) {
|
|
5917
|
-
const api2 = getGitBeaker({
|
|
5918
|
-
url: repoUrl,
|
|
5919
|
-
gitlabAuthToken: options?.gitlabAuthToken
|
|
5920
|
-
});
|
|
5921
|
-
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
5922
|
-
const project = await api2.Projects.show(projectPath);
|
|
5923
|
-
if (!project.default_branch) {
|
|
5924
|
-
throw new Error("no default branch");
|
|
5925
|
-
}
|
|
5926
|
-
return project.default_branch;
|
|
5927
|
-
}
|
|
5928
|
-
async function getGitlabReferenceData({ ref, gitlabUrl }, options) {
|
|
5929
|
-
const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
|
|
5930
|
-
const api2 = getGitBeaker({
|
|
5931
|
-
url: gitlabUrl,
|
|
5932
|
-
gitlabAuthToken: options?.gitlabAuthToken
|
|
5933
|
-
});
|
|
5934
|
-
const results = await Promise.allSettled([
|
|
5935
|
-
(async () => {
|
|
5936
|
-
const res = await api2.Branches.show(projectPath, ref);
|
|
5937
|
-
return {
|
|
5938
|
-
sha: res.commit.id,
|
|
5939
|
-
type: "BRANCH" /* BRANCH */,
|
|
5940
|
-
date: res.commit.committed_date ? new Date(res.commit.committed_date) : void 0
|
|
5941
|
-
};
|
|
5942
|
-
})(),
|
|
5943
|
-
(async () => {
|
|
5944
|
-
const res = await api2.Commits.show(projectPath, ref);
|
|
5945
|
-
return {
|
|
5946
|
-
sha: res.id,
|
|
5947
|
-
type: "COMMIT" /* COMMIT */,
|
|
5948
|
-
date: res.committed_date ? new Date(res.committed_date) : void 0
|
|
5949
|
-
};
|
|
5950
|
-
})(),
|
|
5951
|
-
(async () => {
|
|
5952
|
-
const res = await api2.Tags.show(projectPath, ref);
|
|
5953
|
-
return {
|
|
5954
|
-
sha: res.commit.id,
|
|
5955
|
-
type: "TAG" /* TAG */,
|
|
5956
|
-
date: res.commit.committed_date ? new Date(res.commit.committed_date) : void 0
|
|
5957
|
-
};
|
|
5958
|
-
})()
|
|
5959
|
-
]);
|
|
5960
|
-
const [branchRes, commitRes, tagRes] = results;
|
|
5961
|
-
if (tagRes.status === "fulfilled") {
|
|
5962
|
-
return tagRes.value;
|
|
5963
|
-
}
|
|
5964
|
-
if (branchRes.status === "fulfilled") {
|
|
5965
|
-
return branchRes.value;
|
|
5966
|
-
}
|
|
5967
|
-
if (commitRes.status === "fulfilled") {
|
|
5968
|
-
return commitRes.value;
|
|
5969
|
-
}
|
|
5970
|
-
throw new RefNotFoundError(`ref: ${ref} does not exist`);
|
|
5971
|
-
}
|
|
5972
|
-
function parseGitlabOwnerAndRepo(gitlabUrl) {
|
|
5973
|
-
gitlabUrl = removeTrailingSlash2(gitlabUrl);
|
|
5974
|
-
const parsingResult = parseScmURL(gitlabUrl, "GitLab" /* GitLab */);
|
|
5975
|
-
if (!parsingResult || !parsingResult.repoName) {
|
|
5976
|
-
throw new InvalidUrlPatternError(`invalid gitlab repo Url ${gitlabUrl}`);
|
|
5977
|
-
}
|
|
5978
|
-
const { organization, repoName, projectPath } = parsingResult;
|
|
5979
|
-
return { owner: organization, repo: repoName, projectPath };
|
|
5980
|
-
}
|
|
5981
|
-
async function getGitlabBlameRanges({ ref, gitlabUrl, path: path8 }, options) {
|
|
5982
|
-
const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
|
|
5983
|
-
const api2 = getGitBeaker({
|
|
5984
|
-
url: gitlabUrl,
|
|
5985
|
-
gitlabAuthToken: options?.gitlabAuthToken
|
|
5986
|
-
});
|
|
5987
|
-
const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path8, ref);
|
|
5988
|
-
let lineNumber = 1;
|
|
5989
|
-
return resp.filter((range) => range.lines).map((range) => {
|
|
5990
|
-
const oldLineNumber = lineNumber;
|
|
5991
|
-
if (!range.lines) {
|
|
5992
|
-
throw new Error("range.lines should not be undefined");
|
|
5993
|
-
}
|
|
5994
|
-
lineNumber += range.lines.length;
|
|
5995
|
-
return {
|
|
5996
|
-
startingLine: oldLineNumber,
|
|
5997
|
-
endingLine: lineNumber - 1,
|
|
5998
|
-
login: range.commit.author_email,
|
|
5999
|
-
email: range.commit.author_email,
|
|
6000
|
-
name: range.commit.author_name
|
|
6001
|
-
};
|
|
6002
|
-
});
|
|
6003
|
-
}
|
|
6004
|
-
async function processBody(response) {
|
|
6005
|
-
const headers = response.headers;
|
|
6006
|
-
const type2 = headers.get("content-type")?.split(";")[0]?.trim();
|
|
6007
|
-
if (type2 === "application/json") {
|
|
6008
|
-
return await response.json();
|
|
6009
|
-
}
|
|
6010
|
-
return await response.text();
|
|
6011
|
-
}
|
|
6012
|
-
async function brokerRequestHandler(endpoint, options) {
|
|
6013
|
-
const { prefixUrl, searchParams } = options || {};
|
|
6014
|
-
let baseUrl;
|
|
6015
|
-
if (prefixUrl) baseUrl = prefixUrl.endsWith("/") ? prefixUrl : `${prefixUrl}/`;
|
|
6016
|
-
const url = new URL(endpoint, baseUrl);
|
|
6017
|
-
url.search = searchParams || "";
|
|
6018
|
-
const dispatcher = url && isBrokerUrl(url.href) ? new ProxyAgent({
|
|
6019
|
-
uri: GIT_PROXY_HOST,
|
|
6020
|
-
requestTls: {
|
|
6021
|
-
rejectUnauthorized: false
|
|
6022
|
-
}
|
|
6023
|
-
}) : void 0;
|
|
6024
|
-
const response = await undiciFetch(url, {
|
|
6025
|
-
headers: options?.headers,
|
|
6026
|
-
method: options?.method,
|
|
6027
|
-
body: options?.body ? String(options?.body) : void 0,
|
|
6028
|
-
dispatcher
|
|
6029
|
-
}).catch((e) => {
|
|
6030
|
-
if (e.name === "TimeoutError" || e.name === "AbortError") {
|
|
6031
|
-
throw new Error("Query timeout was reached");
|
|
6032
|
-
}
|
|
6033
|
-
throw e;
|
|
6034
|
-
});
|
|
6035
|
-
if (response.ok)
|
|
6036
|
-
return {
|
|
6037
|
-
body: await processBody(response),
|
|
6038
|
-
headers: Object.fromEntries(response.headers.entries()),
|
|
6039
|
-
status: response.status
|
|
6040
|
-
};
|
|
6041
|
-
throw new Error(`gitbeaker: ${response.statusText}`);
|
|
6042
|
-
}
|
|
6043
|
-
|
|
6044
|
-
// src/features/analysis/scm/gitlab/GitlabSCMLib.ts
|
|
6045
|
-
var GitlabSCMLib = class extends SCMLib {
|
|
6046
|
-
constructor(url, accessToken, scmOrg) {
|
|
6047
|
-
super(url, accessToken, scmOrg);
|
|
6048
|
-
}
|
|
6049
|
-
async createSubmitRequest(params) {
|
|
6050
|
-
this._validateAccessTokenAndUrl();
|
|
6051
|
-
const { targetBranchName, sourceBranchName, title, body } = params;
|
|
6052
|
-
return String(
|
|
6053
|
-
await createMergeRequest({
|
|
6054
|
-
title,
|
|
6055
|
-
body,
|
|
6056
|
-
targetBranchName,
|
|
6057
|
-
sourceBranchName,
|
|
6058
|
-
repoUrl: this.url,
|
|
6059
|
-
accessToken: this.accessToken
|
|
6060
|
-
})
|
|
6061
|
-
);
|
|
6062
|
-
}
|
|
6063
|
-
async validateParams() {
|
|
6064
|
-
return gitlabValidateParams({
|
|
6065
|
-
url: this.url,
|
|
6066
|
-
accessToken: this.accessToken
|
|
6067
|
-
});
|
|
6068
|
-
}
|
|
6069
|
-
async getRepoList(_scmOrg) {
|
|
6070
|
-
if (!this.accessToken) {
|
|
6071
|
-
console.error("no access token");
|
|
6072
|
-
throw new Error("no access token");
|
|
6073
|
-
}
|
|
6074
|
-
return getGitlabRepoList(this.url, this.accessToken);
|
|
6075
|
-
}
|
|
6076
|
-
async getBranchList() {
|
|
6077
|
-
this._validateAccessTokenAndUrl();
|
|
6078
|
-
return getGitlabBranchList({
|
|
6079
|
-
accessToken: this.accessToken,
|
|
6080
|
-
repoUrl: this.url
|
|
6081
|
-
});
|
|
6082
|
-
}
|
|
6083
|
-
get scmLibType() {
|
|
6084
|
-
return "GITLAB" /* GITLAB */;
|
|
6085
|
-
}
|
|
6086
|
-
getAuthHeaders() {
|
|
6087
|
-
if (!this.accessToken) {
|
|
6088
|
-
return {};
|
|
6089
|
-
}
|
|
6090
|
-
if (this.accessToken.startsWith("glpat-")) {
|
|
6091
|
-
return {
|
|
6092
|
-
"Private-Token": this.accessToken
|
|
6093
|
-
};
|
|
6094
|
-
} else {
|
|
6095
|
-
return { authorization: `Bearer ${this.accessToken}` };
|
|
6096
|
-
}
|
|
6097
|
-
}
|
|
6098
|
-
getDownloadUrl(sha) {
|
|
6099
|
-
const urlObj = new URL(this.url || "");
|
|
6100
|
-
const ProjectId = encodeURIComponent(
|
|
6101
|
-
urlObj.pathname.replace(/^\//, "").replace(/\/$/, "")
|
|
6102
|
-
);
|
|
6103
|
-
return Promise.resolve(
|
|
6104
|
-
//We are moving away from this form as it doesn't work when using a non-human token (group/project token)
|
|
6105
|
-
//Where as the API zip endpoint works with any token
|
|
6106
|
-
//`${this.url}/-/archive/${sha}/${repoName}-${sha}.zip`
|
|
6107
|
-
`${urlObj.origin}/api/v4/projects/${ProjectId}/repository/archive.zip?sha=${sha}`
|
|
6108
|
-
);
|
|
6109
|
-
}
|
|
6110
|
-
async _getUsernameForAuthUrl() {
|
|
6111
|
-
if (this?.accessToken?.startsWith("glpat-")) {
|
|
6112
|
-
return this.getUsername();
|
|
6113
|
-
} else {
|
|
6114
|
-
return "oauth2";
|
|
6115
|
-
}
|
|
6116
|
-
}
|
|
6117
|
-
async getIsRemoteBranch(branch) {
|
|
6118
|
-
this._validateAccessTokenAndUrl();
|
|
6119
|
-
return getGitlabIsRemoteBranch({
|
|
6120
|
-
accessToken: this.accessToken,
|
|
6121
|
-
repoUrl: this.url,
|
|
6122
|
-
branch
|
|
6123
|
-
});
|
|
6124
|
-
}
|
|
6125
|
-
async getUserHasAccessToRepo() {
|
|
6126
|
-
this._validateAccessTokenAndUrl();
|
|
6127
|
-
return getGitlabIsUserCollaborator({
|
|
6128
|
-
accessToken: this.accessToken,
|
|
6129
|
-
repoUrl: this.url
|
|
6130
|
-
});
|
|
6131
|
-
}
|
|
6132
|
-
async getUsername() {
|
|
6133
|
-
this._validateAccessTokenAndUrl();
|
|
6134
|
-
return getGitlabUsername(this.url, this.accessToken);
|
|
6135
|
-
}
|
|
6136
|
-
async getSubmitRequestStatus(scmSubmitRequestId) {
|
|
6137
|
-
this._validateAccessTokenAndUrl();
|
|
6138
|
-
const state = await getGitlabMergeRequestStatus({
|
|
6139
|
-
accessToken: this.accessToken,
|
|
6140
|
-
repoUrl: this.url,
|
|
6141
|
-
mrNumber: Number(scmSubmitRequestId)
|
|
6142
|
-
});
|
|
6143
|
-
switch (state) {
|
|
6144
|
-
case gitlabMergeRequestStatus.merged:
|
|
6145
|
-
return "merged";
|
|
6146
|
-
case gitlabMergeRequestStatus.opened:
|
|
6147
|
-
return "open";
|
|
6148
|
-
case gitlabMergeRequestStatus.closed:
|
|
6149
|
-
return "closed";
|
|
6150
|
-
default:
|
|
6151
|
-
throw new Error(`unknown state ${state}`);
|
|
6152
|
-
}
|
|
6153
|
-
}
|
|
6154
|
-
async addCommentToSubmitRequest(submitRequestId, comment) {
|
|
6155
|
-
this._validateAccessTokenAndUrl();
|
|
6156
|
-
await createMarkdownCommentOnPullRequest({
|
|
6157
|
-
accessToken: this.accessToken,
|
|
6158
|
-
repoUrl: this.url,
|
|
6159
|
-
mrNumber: Number(submitRequestId),
|
|
6160
|
-
markdownComment: comment
|
|
6161
|
-
});
|
|
6162
|
-
}
|
|
6163
|
-
async getRepoBlameRanges(ref, path8) {
|
|
6164
|
-
this._validateUrl();
|
|
6165
|
-
return await getGitlabBlameRanges(
|
|
6166
|
-
{ ref, path: path8, gitlabUrl: this.url },
|
|
6167
|
-
{
|
|
6168
|
-
url: this.url,
|
|
6169
|
-
gitlabAuthToken: this.accessToken
|
|
6170
|
-
}
|
|
6171
|
-
);
|
|
6172
|
-
}
|
|
6173
|
-
async getReferenceData(ref) {
|
|
6174
|
-
this._validateUrl();
|
|
6175
|
-
return await getGitlabReferenceData(
|
|
6176
|
-
{ ref, gitlabUrl: this.url },
|
|
6177
|
-
{
|
|
6178
|
-
url: this.url,
|
|
6179
|
-
gitlabAuthToken: this.accessToken
|
|
6180
|
-
}
|
|
6181
|
-
);
|
|
6182
|
-
}
|
|
6183
|
-
async getRepoDefaultBranch() {
|
|
6184
|
-
this._validateUrl();
|
|
6185
|
-
return await getGitlabRepoDefaultBranch(this.url, {
|
|
6186
|
-
url: this.url,
|
|
6187
|
-
gitlabAuthToken: this.accessToken
|
|
6188
|
-
});
|
|
6189
|
-
}
|
|
6190
|
-
async getSubmitRequestUrl(submitRequestUrl) {
|
|
6191
|
-
this._validateAccessTokenAndUrl();
|
|
6192
|
-
const res = await getGitlabMergeRequest({
|
|
6193
|
-
url: this.url,
|
|
6194
|
-
prNumber: submitRequestUrl,
|
|
6195
|
-
accessToken: this.accessToken
|
|
6196
|
-
});
|
|
6197
|
-
return res.web_url;
|
|
6198
|
-
}
|
|
6199
|
-
async getSubmitRequestId(submitRequestUrl) {
|
|
6200
|
-
const match = submitRequestUrl.match(/\/merge_requests\/(\d+)/);
|
|
6201
|
-
return match?.[1] || "";
|
|
6202
|
-
}
|
|
6203
|
-
async getCommitUrl(commitId) {
|
|
6204
|
-
this._validateAccessTokenAndUrl();
|
|
6205
|
-
const res = await getGitlabCommitUrl({
|
|
6206
|
-
url: this.url,
|
|
6207
|
-
commitSha: commitId,
|
|
6208
|
-
accessToken: this.accessToken
|
|
6209
|
-
});
|
|
6210
|
-
return res.web_url;
|
|
6211
|
-
}
|
|
6212
|
-
};
|
|
6213
|
-
|
|
6214
|
-
// src/features/analysis/scm/scmFactory.ts
|
|
6215
|
-
import { z as z23 } from "zod";
|
|
6216
|
-
|
|
6217
|
-
// src/features/analysis/scm/StubSCMLib.ts
|
|
6218
|
-
var StubSCMLib = class extends SCMLib {
|
|
6219
|
-
constructor(url, accessToken, scmOrg) {
|
|
6220
|
-
super(url, accessToken, scmOrg);
|
|
6221
|
-
}
|
|
6222
|
-
async getUrlWithCredentials() {
|
|
6223
|
-
console.warn("getUrlWithCredentials() returning empty string");
|
|
6224
|
-
return "";
|
|
6225
|
-
}
|
|
6226
|
-
async createSubmitRequest(_params) {
|
|
6227
|
-
console.warn("createSubmitRequest() returning empty string");
|
|
6228
|
-
return "";
|
|
6229
|
-
}
|
|
6230
|
-
get scmLibType() {
|
|
6231
|
-
console.warn("scmLibType returning GITHUB as default");
|
|
6232
|
-
return "GITHUB" /* GITHUB */;
|
|
6233
|
-
}
|
|
6234
|
-
getAuthHeaders() {
|
|
6235
|
-
console.warn("getAuthHeaders() returning empty object");
|
|
6236
|
-
return {};
|
|
6237
|
-
}
|
|
6238
|
-
async getDownloadUrl(_sha) {
|
|
6239
|
-
console.warn("getDownloadUrl() returning empty string");
|
|
6240
|
-
return "";
|
|
6241
|
-
}
|
|
6242
|
-
async getIsRemoteBranch(_branch) {
|
|
6243
|
-
console.warn("getIsRemoteBranch() returning false");
|
|
6244
|
-
return false;
|
|
6245
|
-
}
|
|
6246
|
-
async validateParams() {
|
|
6247
|
-
console.warn("validateParams() no-op");
|
|
6248
|
-
}
|
|
6249
|
-
async getRepoList(_scmOrg) {
|
|
6250
|
-
console.warn("getRepoList() returning empty array");
|
|
6251
|
-
return [];
|
|
6252
|
-
}
|
|
6253
|
-
async getBranchList() {
|
|
6254
|
-
console.warn("getBranchList() returning empty array");
|
|
6255
|
-
return [];
|
|
6256
|
-
}
|
|
6257
|
-
async getUsername() {
|
|
6258
|
-
console.warn("getUsername() returning empty string");
|
|
6259
|
-
return "";
|
|
6260
|
-
}
|
|
6261
|
-
async getSubmitRequestStatus(_scmSubmitRequestId) {
|
|
6262
|
-
console.warn("getSubmitRequestStatus() returning ERROR");
|
|
6263
|
-
return "error";
|
|
6264
|
-
}
|
|
6265
|
-
async getUserHasAccessToRepo() {
|
|
6266
|
-
console.warn("getUserHasAccessToRepo() returning false");
|
|
6267
|
-
return false;
|
|
6268
|
-
}
|
|
6269
|
-
async getRepoBlameRanges(_ref, _path) {
|
|
6270
|
-
console.warn("getRepoBlameRanges() returning empty array");
|
|
6271
|
-
return [];
|
|
6272
|
-
}
|
|
6273
|
-
async getReferenceData(_ref) {
|
|
6274
|
-
console.warn("getReferenceData() returning null/empty defaults");
|
|
6275
|
-
return {
|
|
6276
|
-
type: "BRANCH" /* BRANCH */,
|
|
6277
|
-
sha: "",
|
|
6278
|
-
date: void 0
|
|
6279
|
-
};
|
|
6280
|
-
}
|
|
6281
|
-
async getRepoDefaultBranch() {
|
|
6282
|
-
console.warn("getRepoDefaultBranch() returning empty string");
|
|
6283
|
-
return "";
|
|
6284
|
-
}
|
|
6285
|
-
async getSubmitRequestUrl(_submitRequestIdNumber) {
|
|
6286
|
-
console.warn("getSubmitRequestUrl() returning empty string");
|
|
6287
|
-
return "";
|
|
6288
|
-
}
|
|
6289
|
-
async getSubmitRequestId(_submitRequestUrl) {
|
|
6290
|
-
console.warn("getSubmitRequestId() returning empty string");
|
|
6291
|
-
return "";
|
|
6292
|
-
}
|
|
6293
|
-
async getCommitUrl(_commitId) {
|
|
6294
|
-
console.warn("getCommitUrl() returning empty string");
|
|
6295
|
-
return "";
|
|
6296
|
-
}
|
|
6297
|
-
async _getUsernameForAuthUrl() {
|
|
6298
|
-
console.warn("_getUsernameForAuthUrl() returning empty string");
|
|
6299
|
-
return "";
|
|
6300
|
-
}
|
|
6301
|
-
async addCommentToSubmitRequest(_submitRequestId, _comment) {
|
|
6302
|
-
console.warn("addCommentToSubmitRequest() no-op");
|
|
6303
|
-
}
|
|
6304
|
-
};
|
|
6305
|
-
|
|
6306
|
-
// src/features/analysis/scm/scmFactory.ts
|
|
6307
|
-
async function createScmLib({ url, accessToken, scmType, scmOrg }, { propagateExceptions = false } = {}) {
|
|
6308
|
-
const trimmedUrl = url ? url.trim().replace(/\/$/, "").replace(/.git$/i, "") : void 0;
|
|
6309
|
-
try {
|
|
6310
|
-
switch (scmType) {
|
|
6311
|
-
case "GITHUB" /* GITHUB */: {
|
|
6312
|
-
const scm = new GithubSCMLib(trimmedUrl, accessToken, scmOrg);
|
|
6313
|
-
await scm.validateParams();
|
|
6314
|
-
return scm;
|
|
6315
|
-
}
|
|
6316
|
-
case "GITLAB" /* GITLAB */: {
|
|
6317
|
-
const scm = new GitlabSCMLib(trimmedUrl, accessToken, scmOrg);
|
|
6318
|
-
await scm.validateParams();
|
|
6319
|
-
return scm;
|
|
6320
|
-
}
|
|
6321
|
-
case "ADO" /* ADO */: {
|
|
6322
|
-
const scm = new AdoSCMLib(trimmedUrl, accessToken, scmOrg);
|
|
6323
|
-
await scm.getAdoSdk();
|
|
6324
|
-
await scm.validateParams();
|
|
6325
|
-
return scm;
|
|
6326
|
-
}
|
|
6327
|
-
case "BITBUCKET" /* BITBUCKET */: {
|
|
6328
|
-
const scm = new BitbucketSCMLib(trimmedUrl, accessToken, scmOrg);
|
|
6329
|
-
await scm.validateParams();
|
|
6330
|
-
return scm;
|
|
6331
|
-
}
|
|
6332
|
-
}
|
|
6333
|
-
} catch (e) {
|
|
6334
|
-
if (e instanceof InvalidRepoUrlError && url) {
|
|
6335
|
-
throw new RepoNoTokenAccessError(
|
|
6336
|
-
"no access to repo",
|
|
6337
|
-
scmLibScmTypeToScmType[z23.nativeEnum(ScmLibScmType).parse(scmType)]
|
|
6338
|
-
);
|
|
6339
|
-
}
|
|
6340
|
-
console.error(`error validating scm: ${scmType} `, e);
|
|
6341
|
-
if (propagateExceptions) {
|
|
6342
|
-
throw e;
|
|
6343
|
-
}
|
|
6344
|
-
}
|
|
6345
|
-
return new StubSCMLib(trimmedUrl, void 0, void 0);
|
|
6346
|
-
}
|
|
6347
|
-
|
|
6348
|
-
// src/features/analysis/scm/github/utils/utils.ts
|
|
6349
|
-
function parseGithubOwnerAndRepo(gitHubUrl) {
|
|
6350
|
-
gitHubUrl = normalizeUrl(gitHubUrl);
|
|
6351
|
-
const parsingResult = parseScmURL(gitHubUrl, "GitHub" /* GitHub */);
|
|
6352
|
-
if (!parsingResult) {
|
|
6353
|
-
throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
|
|
6354
|
-
}
|
|
6355
|
-
const { organization, repoName } = parsingResult;
|
|
6356
|
-
if (!organization || !repoName) {
|
|
6357
|
-
throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
|
|
6358
|
-
}
|
|
6359
|
-
return { owner: organization, repo: repoName };
|
|
6360
|
-
}
|
|
6361
|
-
function isGithubOnPrem(url) {
|
|
6362
|
-
if (!url) {
|
|
6363
|
-
return false;
|
|
6364
|
-
}
|
|
6365
|
-
return !url.includes(scmCloudUrl.GitHub);
|
|
6366
|
-
}
|
|
6367
|
-
function getFetch(url) {
|
|
6368
|
-
if (url && isBrokerUrl(url)) {
|
|
6369
|
-
const dispatcher = new ProxyAgent2({
|
|
6370
|
-
uri: GIT_PROXY_HOST,
|
|
6371
|
-
requestTls: {
|
|
6372
|
-
rejectUnauthorized: false
|
|
6373
|
-
}
|
|
6374
|
-
});
|
|
6375
|
-
return (input, init) => {
|
|
6376
|
-
return fetch2(input, {
|
|
6377
|
-
...init,
|
|
6378
|
-
dispatcher
|
|
6379
|
-
});
|
|
6380
|
-
};
|
|
6381
|
-
}
|
|
6382
|
-
return fetch2;
|
|
6383
|
-
}
|
|
6384
|
-
function getRandomGithubCloudAnonToken() {
|
|
6385
|
-
if (!GITHUB_API_TOKEN || typeof GITHUB_API_TOKEN !== "string") {
|
|
6386
|
-
return void 0;
|
|
6387
|
-
}
|
|
6388
|
-
const tokens = GITHUB_API_TOKEN.split(",");
|
|
6389
|
-
return tokens[Math.floor(Math.random() * tokens.length)];
|
|
6390
|
-
}
|
|
6391
|
-
function getOctoKit(options) {
|
|
6392
|
-
const token = !options?.auth && !isGithubOnPrem(options?.url) ? getRandomGithubCloudAnonToken() : options?.auth;
|
|
6393
|
-
const baseUrl = options?.url && isGithubOnPrem(options.url) ? `${new URL(options.url).origin}/api/v3` : void 0;
|
|
6394
|
-
return new Octokit({
|
|
6395
|
-
...options,
|
|
6396
|
-
auth: token,
|
|
6397
|
-
baseUrl,
|
|
6398
|
-
//GITHUB_API_TOKEN is only defined in the backend and not when running Bugsy as CLI. We want to enable these debug logs in the backend
|
|
6399
|
-
//to debug the performance of these API calls.
|
|
6400
|
-
log: GITHUB_API_TOKEN ? console : void 0,
|
|
6401
|
-
request: {
|
|
6402
|
-
fetch: getFetch(baseUrl)
|
|
6403
|
-
},
|
|
6404
|
-
retry: {
|
|
6405
|
-
enabled: false
|
|
6406
|
-
},
|
|
6407
|
-
throttle: {
|
|
6408
|
-
enabled: false
|
|
6409
|
-
}
|
|
6410
|
-
});
|
|
6411
|
-
}
|
|
6412
|
-
function isGithubActionActionToken(token) {
|
|
6413
|
-
return token.startsWith("ghs_");
|
|
6414
|
-
}
|
|
6415
|
-
async function githubValidateParams(url, accessToken) {
|
|
6416
|
-
try {
|
|
6417
|
-
const oktoKit = getOctoKit({ auth: accessToken, url });
|
|
6418
|
-
if (accessToken && !isGithubActionActionToken(accessToken)) {
|
|
6419
|
-
await oktoKit.rest.users.getAuthenticated();
|
|
6420
|
-
}
|
|
6421
|
-
if (url && shouldValidateUrl(url)) {
|
|
6422
|
-
const { owner, repo } = parseGithubOwnerAndRepo(url);
|
|
6423
|
-
await oktoKit.request(GET_REPO_BRANCHES, {
|
|
6424
|
-
owner,
|
|
6425
|
-
repo,
|
|
6426
|
-
per_page: 1
|
|
6427
|
-
});
|
|
6428
|
-
}
|
|
6429
|
-
} catch (e) {
|
|
6430
|
-
console.log("could not init github scm", e);
|
|
6431
|
-
const error = e;
|
|
6432
|
-
const code = error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
|
|
6433
|
-
if (code === 401 || code === 403) {
|
|
6434
|
-
throw new InvalidAccessTokenError(`invalid github access token`);
|
|
6435
|
-
}
|
|
6436
|
-
if (code === 404) {
|
|
6437
|
-
throw new InvalidRepoUrlError(`invalid github repo Url ${url}`);
|
|
6438
|
-
}
|
|
6439
|
-
console.log("githubValidateParams error", e);
|
|
6440
|
-
throw new InvalidRepoUrlError(
|
|
6441
|
-
`cannot access GH repo URL: ${url} with the provided access token`
|
|
6442
|
-
);
|
|
5808
|
+
if (code === 404) {
|
|
5809
|
+
throw new InvalidRepoUrlError(`invalid github repo Url ${url}`);
|
|
5810
|
+
}
|
|
5811
|
+
console.log("githubValidateParams error", e);
|
|
5812
|
+
throw new InvalidRepoUrlError(
|
|
5813
|
+
`cannot access GH repo URL: ${url} with the provided access token`
|
|
5814
|
+
);
|
|
6443
5815
|
}
|
|
6444
5816
|
}
|
|
6445
5817
|
|
|
@@ -6610,457 +5982,1143 @@ function getGithubSdk(params = {}) {
|
|
|
6610
5982
|
throw e;
|
|
6611
5983
|
}
|
|
6612
5984
|
},
|
|
6613
|
-
async getBranch({
|
|
6614
|
-
branch,
|
|
6615
|
-
owner,
|
|
6616
|
-
repo
|
|
6617
|
-
}) {
|
|
6618
|
-
return octokit.rest.repos.getBranch({
|
|
6619
|
-
branch,
|
|
5985
|
+
async getBranch({
|
|
5986
|
+
branch,
|
|
5987
|
+
owner,
|
|
5988
|
+
repo
|
|
5989
|
+
}) {
|
|
5990
|
+
return octokit.rest.repos.getBranch({
|
|
5991
|
+
branch,
|
|
5992
|
+
owner,
|
|
5993
|
+
repo
|
|
5994
|
+
});
|
|
5995
|
+
},
|
|
5996
|
+
async getCommit({
|
|
5997
|
+
commitSha,
|
|
5998
|
+
owner,
|
|
5999
|
+
repo
|
|
6000
|
+
}) {
|
|
6001
|
+
return octokit.rest.git.getCommit({
|
|
6002
|
+
repo,
|
|
6003
|
+
owner,
|
|
6004
|
+
commit_sha: commitSha
|
|
6005
|
+
});
|
|
6006
|
+
},
|
|
6007
|
+
async getTagDate({
|
|
6008
|
+
tag,
|
|
6009
|
+
owner,
|
|
6010
|
+
repo
|
|
6011
|
+
}) {
|
|
6012
|
+
const refResponse = await octokit.rest.git.getRef({
|
|
6013
|
+
ref: `tags/${tag}`,
|
|
6014
|
+
owner,
|
|
6015
|
+
repo
|
|
6016
|
+
});
|
|
6017
|
+
const tagSha = refResponse.data.object.sha;
|
|
6018
|
+
if (refResponse.data.object.type === "commit") {
|
|
6019
|
+
const res2 = await octokit.rest.git.getCommit({
|
|
6020
|
+
commit_sha: tagSha,
|
|
6021
|
+
owner,
|
|
6022
|
+
repo
|
|
6023
|
+
});
|
|
6024
|
+
return {
|
|
6025
|
+
date: res2.data.committer.date,
|
|
6026
|
+
sha: res2.data.sha
|
|
6027
|
+
};
|
|
6028
|
+
}
|
|
6029
|
+
const res = await octokit.rest.git.getTag({
|
|
6030
|
+
tag_sha: tagSha,
|
|
6031
|
+
owner,
|
|
6032
|
+
repo
|
|
6033
|
+
});
|
|
6034
|
+
return {
|
|
6035
|
+
date: res.data.tagger.date,
|
|
6036
|
+
sha: res.data.sha
|
|
6037
|
+
};
|
|
6038
|
+
},
|
|
6039
|
+
async getGithubBlameRanges(params2) {
|
|
6040
|
+
const { ref, gitHubUrl, path: path8 } = params2;
|
|
6041
|
+
const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
|
|
6042
|
+
const res = await octokit.graphql(
|
|
6043
|
+
GET_BLAME_DOCUMENT,
|
|
6044
|
+
{
|
|
6045
|
+
owner,
|
|
6046
|
+
repo,
|
|
6047
|
+
path: path8,
|
|
6048
|
+
ref
|
|
6049
|
+
}
|
|
6050
|
+
);
|
|
6051
|
+
if (!res?.repository?.object?.blame?.ranges) {
|
|
6052
|
+
return [];
|
|
6053
|
+
}
|
|
6054
|
+
return res.repository.object.blame.ranges.map((range) => ({
|
|
6055
|
+
startingLine: range.startingLine,
|
|
6056
|
+
endingLine: range.endingLine,
|
|
6057
|
+
email: range.commit.author.user?.email || "",
|
|
6058
|
+
name: range.commit.author.user?.name || "",
|
|
6059
|
+
login: range.commit.author.user?.login || ""
|
|
6060
|
+
}));
|
|
6061
|
+
},
|
|
6062
|
+
// todo: refactor the name for this function
|
|
6063
|
+
async createPr(params2) {
|
|
6064
|
+
const { sourceRepoUrl, filesPaths, userRepoUrl, title, body } = params2;
|
|
6065
|
+
const { owner: sourceOwner, repo: sourceRepo } = parseGithubOwnerAndRepo(sourceRepoUrl);
|
|
6066
|
+
const { owner, repo } = parseGithubOwnerAndRepo(userRepoUrl);
|
|
6067
|
+
const [sourceFilePath, secondFilePath] = filesPaths;
|
|
6068
|
+
const sourceFileContentResponse = await octokit.rest.repos.getContent({
|
|
6069
|
+
owner: sourceOwner,
|
|
6070
|
+
repo: sourceRepo,
|
|
6071
|
+
path: "/" + sourceFilePath
|
|
6072
|
+
});
|
|
6073
|
+
const { data: repository } = await octokit.rest.repos.get({ owner, repo });
|
|
6074
|
+
const defaultBranch = repository.default_branch;
|
|
6075
|
+
const newBranchName = `mobb/workflow-${Date.now()}`;
|
|
6076
|
+
await octokit.rest.git.createRef({
|
|
6077
|
+
owner,
|
|
6078
|
+
repo,
|
|
6079
|
+
ref: `refs/heads/${newBranchName}`,
|
|
6080
|
+
sha: await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha)
|
|
6081
|
+
});
|
|
6082
|
+
const decodedContent = Buffer.from(
|
|
6083
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6084
|
+
// @ts-ignore
|
|
6085
|
+
sourceFileContentResponse.data.content,
|
|
6086
|
+
"base64"
|
|
6087
|
+
).toString("utf-8");
|
|
6088
|
+
const tree = [
|
|
6089
|
+
{
|
|
6090
|
+
path: sourceFilePath,
|
|
6091
|
+
mode: "100644",
|
|
6092
|
+
type: "blob",
|
|
6093
|
+
content: decodedContent
|
|
6094
|
+
}
|
|
6095
|
+
];
|
|
6096
|
+
if (secondFilePath) {
|
|
6097
|
+
const secondFileContentResponse = await octokit.rest.repos.getContent({
|
|
6098
|
+
owner: sourceOwner,
|
|
6099
|
+
repo: sourceRepo,
|
|
6100
|
+
path: "/" + secondFilePath
|
|
6101
|
+
});
|
|
6102
|
+
const secondDecodedContent = Buffer.from(
|
|
6103
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6104
|
+
// @ts-ignore
|
|
6105
|
+
secondFileContentResponse.data.content,
|
|
6106
|
+
"base64"
|
|
6107
|
+
).toString("utf-8");
|
|
6108
|
+
tree.push({
|
|
6109
|
+
path: secondFilePath,
|
|
6110
|
+
mode: "100644",
|
|
6111
|
+
type: "blob",
|
|
6112
|
+
content: secondDecodedContent
|
|
6113
|
+
});
|
|
6114
|
+
}
|
|
6115
|
+
const createTreeResponse = await octokit.rest.git.createTree({
|
|
6116
|
+
owner,
|
|
6117
|
+
repo,
|
|
6118
|
+
base_tree: await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha),
|
|
6119
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6120
|
+
// @ts-ignore
|
|
6121
|
+
tree
|
|
6122
|
+
});
|
|
6123
|
+
const createCommitResponse = await octokit.rest.git.createCommit({
|
|
6124
|
+
owner,
|
|
6125
|
+
repo,
|
|
6126
|
+
message: "Add new yaml file",
|
|
6127
|
+
tree: createTreeResponse.data.sha,
|
|
6128
|
+
parents: [
|
|
6129
|
+
await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha)
|
|
6130
|
+
]
|
|
6131
|
+
});
|
|
6132
|
+
await octokit.rest.git.updateRef({
|
|
6133
|
+
owner,
|
|
6134
|
+
repo,
|
|
6135
|
+
ref: `heads/${newBranchName}`,
|
|
6136
|
+
sha: createCommitResponse.data.sha
|
|
6137
|
+
});
|
|
6138
|
+
const createPRResponse = await octokit.rest.pulls.create({
|
|
6139
|
+
owner,
|
|
6140
|
+
repo,
|
|
6141
|
+
title,
|
|
6142
|
+
head: newBranchName,
|
|
6143
|
+
head_repo: sourceRepo,
|
|
6144
|
+
body,
|
|
6145
|
+
base: defaultBranch
|
|
6146
|
+
});
|
|
6147
|
+
return {
|
|
6148
|
+
pull_request_url: createPRResponse.data.html_url
|
|
6149
|
+
};
|
|
6150
|
+
},
|
|
6151
|
+
async getGithubBranchList(repoUrl) {
|
|
6152
|
+
const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
|
|
6153
|
+
return octokit.rest.repos.listBranches({
|
|
6154
|
+
owner,
|
|
6155
|
+
repo,
|
|
6156
|
+
per_page: MAX_BRANCHES_FETCH,
|
|
6157
|
+
page: 1
|
|
6158
|
+
});
|
|
6159
|
+
},
|
|
6160
|
+
async createPullRequest(options) {
|
|
6161
|
+
const { owner, repo } = parseGithubOwnerAndRepo(options.repoUrl);
|
|
6162
|
+
return octokit.rest.pulls.create({
|
|
6620
6163
|
owner,
|
|
6621
|
-
repo
|
|
6164
|
+
repo,
|
|
6165
|
+
title: options.title,
|
|
6166
|
+
body: options.body,
|
|
6167
|
+
head: options.sourceBranchName,
|
|
6168
|
+
base: options.targetBranchName,
|
|
6169
|
+
draft: false,
|
|
6170
|
+
maintainer_can_modify: true
|
|
6622
6171
|
});
|
|
6623
6172
|
},
|
|
6624
|
-
async
|
|
6625
|
-
|
|
6173
|
+
async forkRepo(options) {
|
|
6174
|
+
const { owner, repo } = parseGithubOwnerAndRepo(options.repoUrl);
|
|
6175
|
+
const createForkRes = await octokit.rest.repos.createFork({
|
|
6176
|
+
owner,
|
|
6177
|
+
repo,
|
|
6178
|
+
default_branch_only: false
|
|
6179
|
+
});
|
|
6180
|
+
return { url: createForkRes.data.html_url };
|
|
6181
|
+
},
|
|
6182
|
+
async getUserInfo() {
|
|
6183
|
+
return octokit.request(GET_USER);
|
|
6184
|
+
}
|
|
6185
|
+
};
|
|
6186
|
+
}
|
|
6187
|
+
|
|
6188
|
+
// src/features/analysis/scm/github/GithubSCMLib.ts
|
|
6189
|
+
var GithubSCMLib = class extends SCMLib {
|
|
6190
|
+
// we don't always need a url, what's important is that we have an access token
|
|
6191
|
+
constructor(url, accessToken, scmOrg) {
|
|
6192
|
+
super(url, accessToken, scmOrg);
|
|
6193
|
+
__publicField(this, "githubSdk");
|
|
6194
|
+
this.githubSdk = getGithubSdk({
|
|
6195
|
+
auth: accessToken,
|
|
6196
|
+
url
|
|
6197
|
+
});
|
|
6198
|
+
}
|
|
6199
|
+
async createSubmitRequest(params) {
|
|
6200
|
+
this._validateAccessTokenAndUrl();
|
|
6201
|
+
const { targetBranchName, sourceBranchName, title, body } = params;
|
|
6202
|
+
const pullRequestResult = await this.githubSdk.createPullRequest({
|
|
6203
|
+
title,
|
|
6204
|
+
body,
|
|
6205
|
+
targetBranchName,
|
|
6206
|
+
sourceBranchName,
|
|
6207
|
+
repoUrl: this.url
|
|
6208
|
+
});
|
|
6209
|
+
return String(pullRequestResult.data.number);
|
|
6210
|
+
}
|
|
6211
|
+
async forkRepo(repoUrl) {
|
|
6212
|
+
this._validateAccessToken();
|
|
6213
|
+
return this.githubSdk.forkRepo({
|
|
6214
|
+
repoUrl
|
|
6215
|
+
});
|
|
6216
|
+
}
|
|
6217
|
+
async createOrUpdateRepositorySecret(params) {
|
|
6218
|
+
this._validateAccessTokenAndUrl();
|
|
6219
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6220
|
+
const { data: repositoryPublicKeyResponse } = await this.githubSdk.getRepositoryPublicKey({ owner, repo });
|
|
6221
|
+
const { key_id, key } = repositoryPublicKeyResponse;
|
|
6222
|
+
const encryptedValue = await encryptSecret(params.value, key);
|
|
6223
|
+
return this.githubSdk.createOrUpdateRepositorySecret({
|
|
6224
|
+
encrypted_value: encryptedValue,
|
|
6225
|
+
secret_name: params.name,
|
|
6226
|
+
key_id,
|
|
6227
|
+
owner,
|
|
6228
|
+
repo
|
|
6229
|
+
});
|
|
6230
|
+
}
|
|
6231
|
+
async createPullRequestWithNewFile(sourceRepoUrl, filesPaths, userRepoUrl, title, body) {
|
|
6232
|
+
const { pull_request_url } = await this.githubSdk.createPr({
|
|
6233
|
+
sourceRepoUrl,
|
|
6234
|
+
filesPaths,
|
|
6235
|
+
userRepoUrl,
|
|
6236
|
+
title,
|
|
6237
|
+
body
|
|
6238
|
+
});
|
|
6239
|
+
return { pull_request_url };
|
|
6240
|
+
}
|
|
6241
|
+
async validateParams() {
|
|
6242
|
+
return githubValidateParams(this.url, this.accessToken);
|
|
6243
|
+
}
|
|
6244
|
+
async postPrComment(params) {
|
|
6245
|
+
this._validateAccessTokenAndUrl();
|
|
6246
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6247
|
+
return this.githubSdk.postPrComment({
|
|
6248
|
+
...params,
|
|
6249
|
+
owner,
|
|
6250
|
+
repo
|
|
6251
|
+
});
|
|
6252
|
+
}
|
|
6253
|
+
async updatePrComment(params) {
|
|
6254
|
+
this._validateAccessTokenAndUrl();
|
|
6255
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6256
|
+
return this.githubSdk.updatePrComment({
|
|
6257
|
+
...params,
|
|
6258
|
+
owner,
|
|
6259
|
+
repo
|
|
6260
|
+
});
|
|
6261
|
+
}
|
|
6262
|
+
async deleteComment(params) {
|
|
6263
|
+
this._validateAccessTokenAndUrl();
|
|
6264
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6265
|
+
return this.githubSdk.deleteComment({
|
|
6266
|
+
...params,
|
|
6267
|
+
owner,
|
|
6268
|
+
repo
|
|
6269
|
+
});
|
|
6270
|
+
}
|
|
6271
|
+
async getPrComments(params) {
|
|
6272
|
+
this._validateAccessTokenAndUrl();
|
|
6273
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6274
|
+
return this.githubSdk.getPrComments({
|
|
6275
|
+
per_page: 100,
|
|
6276
|
+
...params,
|
|
6277
|
+
owner,
|
|
6278
|
+
repo
|
|
6279
|
+
});
|
|
6280
|
+
}
|
|
6281
|
+
async getPrDiff(params) {
|
|
6282
|
+
this._validateAccessTokenAndUrl();
|
|
6283
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6284
|
+
const prRes = await this.githubSdk.getPrDiff({
|
|
6285
|
+
...params,
|
|
6286
|
+
owner,
|
|
6287
|
+
repo
|
|
6288
|
+
});
|
|
6289
|
+
return z22.string().parse(prRes.data);
|
|
6290
|
+
}
|
|
6291
|
+
async getRepoList(_scmOrg) {
|
|
6292
|
+
this._validateAccessToken();
|
|
6293
|
+
return this.githubSdk.getGithubRepoList();
|
|
6294
|
+
}
|
|
6295
|
+
async getBranchList() {
|
|
6296
|
+
this._validateAccessTokenAndUrl();
|
|
6297
|
+
const branches = await this.githubSdk.getGithubBranchList(this.url);
|
|
6298
|
+
return branches.data.map((branch) => branch.name);
|
|
6299
|
+
}
|
|
6300
|
+
get scmLibType() {
|
|
6301
|
+
return "GITHUB" /* GITHUB */;
|
|
6302
|
+
}
|
|
6303
|
+
getAuthHeaders() {
|
|
6304
|
+
if (this.accessToken) {
|
|
6305
|
+
return { authorization: `Bearer ${this.accessToken}` };
|
|
6306
|
+
}
|
|
6307
|
+
return {};
|
|
6308
|
+
}
|
|
6309
|
+
getDownloadUrl(sha) {
|
|
6310
|
+
this._validateUrl();
|
|
6311
|
+
const res = parseScmURL(this.url, "GitHub" /* GitHub */);
|
|
6312
|
+
if (!res) {
|
|
6313
|
+
throw new InvalidRepoUrlError("invalid repo url");
|
|
6314
|
+
}
|
|
6315
|
+
const { protocol, hostname, organization, repoName } = res;
|
|
6316
|
+
const downloadUrl = isGithubOnPrem(this.url) ? `${protocol}//${hostname}/api/v3/repos/${organization}/${repoName}/zipball/${sha}` : `https://api.${hostname}/repos/${organization}/${repoName}/zipball/${sha}`;
|
|
6317
|
+
return Promise.resolve(downloadUrl);
|
|
6318
|
+
}
|
|
6319
|
+
async _getUsernameForAuthUrl() {
|
|
6320
|
+
return this.getUsername();
|
|
6321
|
+
}
|
|
6322
|
+
async getIsRemoteBranch(branch) {
|
|
6323
|
+
this._validateUrl();
|
|
6324
|
+
return this.githubSdk.getGithubIsRemoteBranch({ branch, repoUrl: this.url });
|
|
6325
|
+
}
|
|
6326
|
+
async getUserHasAccessToRepo() {
|
|
6327
|
+
this._validateAccessTokenAndUrl();
|
|
6328
|
+
const username = await this.getUsername();
|
|
6329
|
+
return this.githubSdk.getGithubIsUserCollaborator({
|
|
6330
|
+
repoUrl: this.url,
|
|
6331
|
+
username
|
|
6332
|
+
});
|
|
6333
|
+
}
|
|
6334
|
+
async getUsername() {
|
|
6335
|
+
this._validateAccessToken();
|
|
6336
|
+
return this.githubSdk.getGithubUsername();
|
|
6337
|
+
}
|
|
6338
|
+
async getSubmitRequestStatus(scmSubmitRequestId) {
|
|
6339
|
+
this._validateAccessTokenAndUrl();
|
|
6340
|
+
return this.githubSdk.getGithubPullRequestStatus({
|
|
6341
|
+
repoUrl: this.url,
|
|
6342
|
+
prNumber: Number(scmSubmitRequestId)
|
|
6343
|
+
});
|
|
6344
|
+
}
|
|
6345
|
+
async addCommentToSubmitRequest(submitRequestId, comment) {
|
|
6346
|
+
this._validateAccessTokenAndUrl();
|
|
6347
|
+
await this.githubSdk.createMarkdownCommentOnPullRequest({
|
|
6348
|
+
repoUrl: this.url,
|
|
6349
|
+
prNumber: Number(submitRequestId),
|
|
6350
|
+
markdownComment: comment
|
|
6351
|
+
});
|
|
6352
|
+
}
|
|
6353
|
+
async getRepoBlameRanges(ref, path8) {
|
|
6354
|
+
this._validateUrl();
|
|
6355
|
+
return await this.githubSdk.getGithubBlameRanges({
|
|
6356
|
+
ref,
|
|
6357
|
+
path: path8,
|
|
6358
|
+
gitHubUrl: this.url
|
|
6359
|
+
});
|
|
6360
|
+
}
|
|
6361
|
+
async getReferenceData(ref) {
|
|
6362
|
+
this._validateUrl();
|
|
6363
|
+
return this.githubSdk.getGithubReferenceData({ ref, gitHubUrl: this.url });
|
|
6364
|
+
}
|
|
6365
|
+
async getPrComment(commentId) {
|
|
6366
|
+
this._validateUrl();
|
|
6367
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6368
|
+
return await this.githubSdk.getPrComment({
|
|
6369
|
+
repo,
|
|
6370
|
+
owner,
|
|
6371
|
+
comment_id: commentId
|
|
6372
|
+
});
|
|
6373
|
+
}
|
|
6374
|
+
async getRepoDefaultBranch() {
|
|
6375
|
+
this._validateUrl();
|
|
6376
|
+
return await this.githubSdk.getGithubRepoDefaultBranch(this.url);
|
|
6377
|
+
}
|
|
6378
|
+
async getSubmitRequestUrl(submitRequestUrl) {
|
|
6379
|
+
this._validateAccessTokenAndUrl();
|
|
6380
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6381
|
+
const getPrRes = await this.githubSdk.getPr({
|
|
6382
|
+
owner,
|
|
6383
|
+
repo,
|
|
6384
|
+
pull_number: submitRequestUrl
|
|
6385
|
+
});
|
|
6386
|
+
return getPrRes.data.html_url;
|
|
6387
|
+
}
|
|
6388
|
+
async getSubmitRequestId(submitRequestUrl) {
|
|
6389
|
+
const match = submitRequestUrl.match(/\/pull\/(\d+)/);
|
|
6390
|
+
return match?.[1] || "";
|
|
6391
|
+
}
|
|
6392
|
+
async getCommitUrl(commitId) {
|
|
6393
|
+
this._validateAccessTokenAndUrl();
|
|
6394
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6395
|
+
const getCommitRes = await this.githubSdk.getCommit({
|
|
6396
|
+
owner,
|
|
6397
|
+
repo,
|
|
6398
|
+
commitSha: commitId
|
|
6399
|
+
});
|
|
6400
|
+
return getCommitRes.data.html_url;
|
|
6401
|
+
}
|
|
6402
|
+
async postGeneralPrComment(params) {
|
|
6403
|
+
const { prNumber, body } = params;
|
|
6404
|
+
this._validateAccessTokenAndUrl();
|
|
6405
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6406
|
+
return await this.githubSdk.postGeneralPrComment({
|
|
6407
|
+
issue_number: prNumber,
|
|
6626
6408
|
owner,
|
|
6627
|
-
repo
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
}
|
|
6635
|
-
|
|
6636
|
-
|
|
6409
|
+
repo,
|
|
6410
|
+
body
|
|
6411
|
+
});
|
|
6412
|
+
}
|
|
6413
|
+
async getGeneralPrComments(params) {
|
|
6414
|
+
const { prNumber } = params;
|
|
6415
|
+
this._validateAccessTokenAndUrl();
|
|
6416
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6417
|
+
return await this.githubSdk.getGeneralPrComments({
|
|
6418
|
+
issue_number: prNumber,
|
|
6637
6419
|
owner,
|
|
6638
6420
|
repo
|
|
6639
|
-
})
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6421
|
+
});
|
|
6422
|
+
}
|
|
6423
|
+
async deleteGeneralPrComment({
|
|
6424
|
+
commentId
|
|
6425
|
+
}) {
|
|
6426
|
+
this._validateAccessTokenAndUrl();
|
|
6427
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6428
|
+
return this.githubSdk.deleteGeneralPrComment({
|
|
6429
|
+
owner,
|
|
6430
|
+
repo,
|
|
6431
|
+
comment_id: commentId
|
|
6432
|
+
});
|
|
6433
|
+
}
|
|
6434
|
+
};
|
|
6435
|
+
|
|
6436
|
+
// src/features/analysis/scm/gitlab/gitlab.ts
|
|
6437
|
+
import querystring3 from "node:querystring";
|
|
6438
|
+
import {
|
|
6439
|
+
createRequesterFn
|
|
6440
|
+
} from "@gitbeaker/requester-utils";
|
|
6441
|
+
import {
|
|
6442
|
+
AccessLevel,
|
|
6443
|
+
Gitlab
|
|
6444
|
+
} from "@gitbeaker/rest";
|
|
6445
|
+
import Debug4 from "debug";
|
|
6446
|
+
import {
|
|
6447
|
+
fetch as undiciFetch,
|
|
6448
|
+
ProxyAgent as ProxyAgent2
|
|
6449
|
+
} from "undici";
|
|
6450
|
+
|
|
6451
|
+
// src/features/analysis/scm/gitlab/types.ts
|
|
6452
|
+
import { z as z23 } from "zod";
|
|
6453
|
+
var GitlabAuthResultZ = z23.object({
|
|
6454
|
+
access_token: z23.string(),
|
|
6455
|
+
token_type: z23.string(),
|
|
6456
|
+
refresh_token: z23.string()
|
|
6457
|
+
});
|
|
6458
|
+
|
|
6459
|
+
// src/features/analysis/scm/gitlab/gitlab.ts
|
|
6460
|
+
var debug4 = Debug4("scm:gitlab");
|
|
6461
|
+
function removeTrailingSlash2(str) {
|
|
6462
|
+
return str.trim().replace(/\/+$/, "");
|
|
6463
|
+
}
|
|
6464
|
+
function getRandomGitlabCloudAnonToken() {
|
|
6465
|
+
if (!GITLAB_API_TOKEN || typeof GITLAB_API_TOKEN !== "string") {
|
|
6466
|
+
return void 0;
|
|
6467
|
+
}
|
|
6468
|
+
const tokens = GITLAB_API_TOKEN.split(",");
|
|
6469
|
+
return tokens[Math.floor(Math.random() * tokens.length)];
|
|
6470
|
+
}
|
|
6471
|
+
function getGitBeaker(options) {
|
|
6472
|
+
const token = options?.gitlabAuthToken ?? getRandomGitlabCloudAnonToken() ?? "";
|
|
6473
|
+
const url = options.url;
|
|
6474
|
+
const host = url ? new URL(url).origin : "https://gitlab.com";
|
|
6475
|
+
if (token?.startsWith("glpat-") || token === "") {
|
|
6476
|
+
return new Gitlab({
|
|
6477
|
+
token,
|
|
6478
|
+
host,
|
|
6479
|
+
requesterFn: createRequesterFn(
|
|
6480
|
+
(_, reqo) => Promise.resolve(reqo),
|
|
6481
|
+
brokerRequestHandler
|
|
6482
|
+
)
|
|
6483
|
+
});
|
|
6484
|
+
}
|
|
6485
|
+
return new Gitlab({
|
|
6486
|
+
oauthToken: token,
|
|
6487
|
+
host,
|
|
6488
|
+
requesterFn: createRequesterFn(
|
|
6489
|
+
(_, reqo) => Promise.resolve(reqo),
|
|
6490
|
+
brokerRequestHandler
|
|
6491
|
+
)
|
|
6492
|
+
});
|
|
6493
|
+
}
|
|
6494
|
+
async function gitlabValidateParams({
|
|
6495
|
+
url,
|
|
6496
|
+
accessToken
|
|
6497
|
+
}) {
|
|
6498
|
+
try {
|
|
6499
|
+
const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
|
|
6500
|
+
if (accessToken) {
|
|
6501
|
+
await api2.Users.showCurrentUser();
|
|
6502
|
+
}
|
|
6503
|
+
if (url && shouldValidateUrl(url)) {
|
|
6504
|
+
const { projectPath } = parseGitlabOwnerAndRepo(url);
|
|
6505
|
+
await api2.Projects.show(projectPath);
|
|
6506
|
+
}
|
|
6507
|
+
} catch (e) {
|
|
6508
|
+
const error = e;
|
|
6509
|
+
const code = error.code || error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
|
|
6510
|
+
const description = error.description || `${e}`;
|
|
6511
|
+
if (code === 401 || code === 403 || description.includes("401") || description.includes("403")) {
|
|
6512
|
+
throw new InvalidAccessTokenError(`invalid gitlab access token`);
|
|
6513
|
+
}
|
|
6514
|
+
if (code === 404 || description.includes("404") || description.includes("Not Found")) {
|
|
6515
|
+
throw new InvalidRepoUrlError(`invalid gitlab repo URL: ${url}`);
|
|
6516
|
+
}
|
|
6517
|
+
console.log("gitlabValidateParams error", e);
|
|
6518
|
+
throw new InvalidRepoUrlError(
|
|
6519
|
+
`cannot access gitlab repo URL: ${url} with the provided access token`
|
|
6520
|
+
);
|
|
6521
|
+
}
|
|
6522
|
+
}
|
|
6523
|
+
async function getGitlabUsername(url, accessToken) {
|
|
6524
|
+
const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
|
|
6525
|
+
const res = await api2.Users.showCurrentUser();
|
|
6526
|
+
return res.username;
|
|
6527
|
+
}
|
|
6528
|
+
async function getGitlabIsUserCollaborator({
|
|
6529
|
+
accessToken,
|
|
6530
|
+
repoUrl
|
|
6531
|
+
}) {
|
|
6532
|
+
try {
|
|
6533
|
+
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
6534
|
+
const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
|
|
6535
|
+
const proj = await api2.Projects.show(projectPath);
|
|
6536
|
+
const groupAccess = proj.permissions?.group_access?.access_level || 0;
|
|
6537
|
+
const projectAccess = proj.permissions?.project_access?.access_level || 0;
|
|
6538
|
+
const accessLevelWithWriteAccess = [
|
|
6539
|
+
AccessLevel.DEVELOPER,
|
|
6540
|
+
AccessLevel.MAINTAINER,
|
|
6541
|
+
AccessLevel.OWNER,
|
|
6542
|
+
AccessLevel.ADMIN
|
|
6543
|
+
];
|
|
6544
|
+
return accessLevelWithWriteAccess.includes(groupAccess) || accessLevelWithWriteAccess.includes(projectAccess);
|
|
6545
|
+
} catch (e) {
|
|
6546
|
+
return false;
|
|
6547
|
+
}
|
|
6548
|
+
}
|
|
6549
|
+
var gitlabMergeRequestStatus = {
|
|
6550
|
+
merged: "merged",
|
|
6551
|
+
opened: "opened",
|
|
6552
|
+
closed: "closed"
|
|
6553
|
+
};
|
|
6554
|
+
async function getGitlabMergeRequestStatus({
|
|
6555
|
+
accessToken,
|
|
6556
|
+
repoUrl,
|
|
6557
|
+
mrNumber
|
|
6558
|
+
}) {
|
|
6559
|
+
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
6560
|
+
const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
|
|
6561
|
+
const res = await api2.MergeRequests.show(projectPath, mrNumber);
|
|
6562
|
+
switch (res.state) {
|
|
6563
|
+
case gitlabMergeRequestStatus.merged:
|
|
6564
|
+
case gitlabMergeRequestStatus.opened:
|
|
6565
|
+
case gitlabMergeRequestStatus.closed:
|
|
6566
|
+
return res.state;
|
|
6567
|
+
default:
|
|
6568
|
+
throw new Error(`unknown merge request state ${res.state}`);
|
|
6569
|
+
}
|
|
6570
|
+
}
|
|
6571
|
+
async function createMarkdownCommentOnPullRequest({
|
|
6572
|
+
markdownComment,
|
|
6573
|
+
accessToken,
|
|
6574
|
+
repoUrl,
|
|
6575
|
+
mrNumber
|
|
6576
|
+
}) {
|
|
6577
|
+
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
6578
|
+
const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
|
|
6579
|
+
return api2.MergeRequestNotes.create(projectPath, mrNumber, markdownComment);
|
|
6580
|
+
}
|
|
6581
|
+
async function getGitlabIsRemoteBranch({
|
|
6582
|
+
accessToken,
|
|
6583
|
+
repoUrl,
|
|
6584
|
+
branch
|
|
6585
|
+
}) {
|
|
6586
|
+
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
6587
|
+
const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
|
|
6588
|
+
try {
|
|
6589
|
+
const res = await api2.Branches.show(projectPath, branch);
|
|
6590
|
+
return res.name === branch;
|
|
6591
|
+
} catch (e) {
|
|
6592
|
+
return false;
|
|
6593
|
+
}
|
|
6594
|
+
}
|
|
6595
|
+
async function getGitlabRepoList(url, accessToken) {
|
|
6596
|
+
const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
|
|
6597
|
+
const res = await api2.Projects.all({
|
|
6598
|
+
membership: true,
|
|
6599
|
+
//TODO: a bug in the sorting mechanism of this api call
|
|
6600
|
+
//disallows us to sort by updated_at in descending order
|
|
6601
|
+
//so we have to sort by updated_at in ascending order.
|
|
6602
|
+
//We can wait for the bug to be fixed or call the api
|
|
6603
|
+
//directly with fetch()
|
|
6604
|
+
sort: "asc",
|
|
6605
|
+
orderBy: "updated_at",
|
|
6606
|
+
perPage: 100
|
|
6607
|
+
});
|
|
6608
|
+
return Promise.all(
|
|
6609
|
+
res.map(async (project) => {
|
|
6610
|
+
const proj = await api2.Projects.show(project.id);
|
|
6611
|
+
const owner = proj.namespace.name;
|
|
6612
|
+
const repoLanguages = await api2.Projects.showLanguages(project.id);
|
|
6613
|
+
return {
|
|
6614
|
+
repoName: project.path,
|
|
6615
|
+
repoUrl: project.web_url,
|
|
6616
|
+
repoOwner: owner,
|
|
6617
|
+
repoLanguages: Object.keys(repoLanguages),
|
|
6618
|
+
repoIsPublic: project.visibility === "public",
|
|
6619
|
+
repoUpdatedAt: project.last_activity_at
|
|
6620
|
+
};
|
|
6621
|
+
})
|
|
6622
|
+
);
|
|
6623
|
+
}
|
|
6624
|
+
async function getGitlabBranchList({
|
|
6625
|
+
accessToken,
|
|
6626
|
+
repoUrl
|
|
6627
|
+
}) {
|
|
6628
|
+
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
6629
|
+
const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
|
|
6630
|
+
try {
|
|
6631
|
+
const res = await api2.Branches.all(projectPath, {
|
|
6632
|
+
//keyset API pagination is not supported by GL for the branch list (at least not the on-prem version)
|
|
6633
|
+
//so for now we stick with the default pagination and just return the first page and limit the results to 1000 entries.
|
|
6634
|
+
//This is a temporary solution until we implement list branches with name search.
|
|
6635
|
+
perPage: MAX_BRANCHES_FETCH,
|
|
6636
|
+
page: 1
|
|
6637
|
+
});
|
|
6638
|
+
res.sort((a, b) => {
|
|
6639
|
+
if (!a.commit?.committed_date || !b.commit?.committed_date) {
|
|
6640
|
+
return 0;
|
|
6656
6641
|
}
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6642
|
+
return new Date(b.commit?.committed_date).getTime() - new Date(a.commit?.committed_date).getTime();
|
|
6643
|
+
});
|
|
6644
|
+
return res.map((branch) => branch.name).slice(0, MAX_BRANCHES_FETCH);
|
|
6645
|
+
} catch (e) {
|
|
6646
|
+
return [];
|
|
6647
|
+
}
|
|
6648
|
+
}
|
|
6649
|
+
async function createMergeRequest(options) {
|
|
6650
|
+
const { projectPath } = parseGitlabOwnerAndRepo(options.repoUrl);
|
|
6651
|
+
const api2 = getGitBeaker({
|
|
6652
|
+
url: options.repoUrl,
|
|
6653
|
+
gitlabAuthToken: options.accessToken
|
|
6654
|
+
});
|
|
6655
|
+
const res = await api2.MergeRequests.create(
|
|
6656
|
+
projectPath,
|
|
6657
|
+
options.sourceBranchName,
|
|
6658
|
+
options.targetBranchName,
|
|
6659
|
+
options.title,
|
|
6660
|
+
{
|
|
6661
|
+
description: options.body
|
|
6662
|
+
}
|
|
6663
|
+
);
|
|
6664
|
+
return res.iid;
|
|
6665
|
+
}
|
|
6666
|
+
async function getGitlabMergeRequest({
|
|
6667
|
+
url,
|
|
6668
|
+
prNumber,
|
|
6669
|
+
accessToken
|
|
6670
|
+
}) {
|
|
6671
|
+
const { projectPath } = parseGitlabOwnerAndRepo(url);
|
|
6672
|
+
const api2 = getGitBeaker({
|
|
6673
|
+
url,
|
|
6674
|
+
gitlabAuthToken: accessToken
|
|
6675
|
+
});
|
|
6676
|
+
return await api2.MergeRequests.show(projectPath, prNumber);
|
|
6677
|
+
}
|
|
6678
|
+
async function getGitlabCommitUrl({
|
|
6679
|
+
url,
|
|
6680
|
+
commitSha,
|
|
6681
|
+
accessToken
|
|
6682
|
+
}) {
|
|
6683
|
+
const { projectPath } = parseGitlabOwnerAndRepo(url);
|
|
6684
|
+
const api2 = getGitBeaker({
|
|
6685
|
+
url,
|
|
6686
|
+
gitlabAuthToken: accessToken
|
|
6687
|
+
});
|
|
6688
|
+
return await api2.Commits.show(projectPath, commitSha);
|
|
6689
|
+
}
|
|
6690
|
+
async function getGitlabRepoDefaultBranch(repoUrl, options) {
|
|
6691
|
+
const api2 = getGitBeaker({
|
|
6692
|
+
url: repoUrl,
|
|
6693
|
+
gitlabAuthToken: options?.gitlabAuthToken
|
|
6694
|
+
});
|
|
6695
|
+
const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
|
|
6696
|
+
const project = await api2.Projects.show(projectPath);
|
|
6697
|
+
if (!project.default_branch) {
|
|
6698
|
+
throw new Error("no default branch");
|
|
6699
|
+
}
|
|
6700
|
+
return project.default_branch;
|
|
6701
|
+
}
|
|
6702
|
+
async function getGitlabReferenceData({ ref, gitlabUrl }, options) {
|
|
6703
|
+
const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
|
|
6704
|
+
const api2 = getGitBeaker({
|
|
6705
|
+
url: gitlabUrl,
|
|
6706
|
+
gitlabAuthToken: options?.gitlabAuthToken
|
|
6707
|
+
});
|
|
6708
|
+
const results = await Promise.allSettled([
|
|
6709
|
+
(async () => {
|
|
6710
|
+
const res = await api2.Branches.show(projectPath, ref);
|
|
6662
6711
|
return {
|
|
6663
|
-
|
|
6664
|
-
|
|
6712
|
+
sha: res.commit.id,
|
|
6713
|
+
type: "BRANCH" /* BRANCH */,
|
|
6714
|
+
date: res.commit.committed_date ? new Date(res.commit.committed_date) : void 0
|
|
6665
6715
|
};
|
|
6666
|
-
},
|
|
6667
|
-
async
|
|
6668
|
-
const
|
|
6669
|
-
const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
|
|
6670
|
-
const res = await octokit.graphql(
|
|
6671
|
-
GET_BLAME_DOCUMENT,
|
|
6672
|
-
{
|
|
6673
|
-
owner,
|
|
6674
|
-
repo,
|
|
6675
|
-
path: path8,
|
|
6676
|
-
ref
|
|
6677
|
-
}
|
|
6678
|
-
);
|
|
6679
|
-
if (!res?.repository?.object?.blame?.ranges) {
|
|
6680
|
-
return [];
|
|
6681
|
-
}
|
|
6682
|
-
return res.repository.object.blame.ranges.map((range) => ({
|
|
6683
|
-
startingLine: range.startingLine,
|
|
6684
|
-
endingLine: range.endingLine,
|
|
6685
|
-
email: range.commit.author.user?.email || "",
|
|
6686
|
-
name: range.commit.author.user?.name || "",
|
|
6687
|
-
login: range.commit.author.user?.login || ""
|
|
6688
|
-
}));
|
|
6689
|
-
},
|
|
6690
|
-
// todo: refactor the name for this function
|
|
6691
|
-
async createPr(params2) {
|
|
6692
|
-
const { sourceRepoUrl, filesPaths, userRepoUrl, title, body } = params2;
|
|
6693
|
-
const { owner: sourceOwner, repo: sourceRepo } = parseGithubOwnerAndRepo(sourceRepoUrl);
|
|
6694
|
-
const { owner, repo } = parseGithubOwnerAndRepo(userRepoUrl);
|
|
6695
|
-
const [sourceFilePath, secondFilePath] = filesPaths;
|
|
6696
|
-
const sourceFileContentResponse = await octokit.rest.repos.getContent({
|
|
6697
|
-
owner: sourceOwner,
|
|
6698
|
-
repo: sourceRepo,
|
|
6699
|
-
path: "/" + sourceFilePath
|
|
6700
|
-
});
|
|
6701
|
-
const { data: repository } = await octokit.rest.repos.get({ owner, repo });
|
|
6702
|
-
const defaultBranch = repository.default_branch;
|
|
6703
|
-
const newBranchName = `mobb/workflow-${Date.now()}`;
|
|
6704
|
-
await octokit.rest.git.createRef({
|
|
6705
|
-
owner,
|
|
6706
|
-
repo,
|
|
6707
|
-
ref: `refs/heads/${newBranchName}`,
|
|
6708
|
-
sha: await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha)
|
|
6709
|
-
});
|
|
6710
|
-
const decodedContent = Buffer.from(
|
|
6711
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6712
|
-
// @ts-ignore
|
|
6713
|
-
sourceFileContentResponse.data.content,
|
|
6714
|
-
"base64"
|
|
6715
|
-
).toString("utf-8");
|
|
6716
|
-
const tree = [
|
|
6717
|
-
{
|
|
6718
|
-
path: sourceFilePath,
|
|
6719
|
-
mode: "100644",
|
|
6720
|
-
type: "blob",
|
|
6721
|
-
content: decodedContent
|
|
6722
|
-
}
|
|
6723
|
-
];
|
|
6724
|
-
if (secondFilePath) {
|
|
6725
|
-
const secondFileContentResponse = await octokit.rest.repos.getContent({
|
|
6726
|
-
owner: sourceOwner,
|
|
6727
|
-
repo: sourceRepo,
|
|
6728
|
-
path: "/" + secondFilePath
|
|
6729
|
-
});
|
|
6730
|
-
const secondDecodedContent = Buffer.from(
|
|
6731
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6732
|
-
// @ts-ignore
|
|
6733
|
-
secondFileContentResponse.data.content,
|
|
6734
|
-
"base64"
|
|
6735
|
-
).toString("utf-8");
|
|
6736
|
-
tree.push({
|
|
6737
|
-
path: secondFilePath,
|
|
6738
|
-
mode: "100644",
|
|
6739
|
-
type: "blob",
|
|
6740
|
-
content: secondDecodedContent
|
|
6741
|
-
});
|
|
6742
|
-
}
|
|
6743
|
-
const createTreeResponse = await octokit.rest.git.createTree({
|
|
6744
|
-
owner,
|
|
6745
|
-
repo,
|
|
6746
|
-
base_tree: await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha),
|
|
6747
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6748
|
-
// @ts-ignore
|
|
6749
|
-
tree
|
|
6750
|
-
});
|
|
6751
|
-
const createCommitResponse = await octokit.rest.git.createCommit({
|
|
6752
|
-
owner,
|
|
6753
|
-
repo,
|
|
6754
|
-
message: "Add new yaml file",
|
|
6755
|
-
tree: createTreeResponse.data.sha,
|
|
6756
|
-
parents: [
|
|
6757
|
-
await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha)
|
|
6758
|
-
]
|
|
6759
|
-
});
|
|
6760
|
-
await octokit.rest.git.updateRef({
|
|
6761
|
-
owner,
|
|
6762
|
-
repo,
|
|
6763
|
-
ref: `heads/${newBranchName}`,
|
|
6764
|
-
sha: createCommitResponse.data.sha
|
|
6765
|
-
});
|
|
6766
|
-
const createPRResponse = await octokit.rest.pulls.create({
|
|
6767
|
-
owner,
|
|
6768
|
-
repo,
|
|
6769
|
-
title,
|
|
6770
|
-
head: newBranchName,
|
|
6771
|
-
head_repo: sourceRepo,
|
|
6772
|
-
body,
|
|
6773
|
-
base: defaultBranch
|
|
6774
|
-
});
|
|
6716
|
+
})(),
|
|
6717
|
+
(async () => {
|
|
6718
|
+
const res = await api2.Commits.show(projectPath, ref);
|
|
6775
6719
|
return {
|
|
6776
|
-
|
|
6720
|
+
sha: res.id,
|
|
6721
|
+
type: "COMMIT" /* COMMIT */,
|
|
6722
|
+
date: res.committed_date ? new Date(res.committed_date) : void 0
|
|
6777
6723
|
};
|
|
6778
|
-
},
|
|
6779
|
-
async
|
|
6780
|
-
const
|
|
6781
|
-
return
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6724
|
+
})(),
|
|
6725
|
+
(async () => {
|
|
6726
|
+
const res = await api2.Tags.show(projectPath, ref);
|
|
6727
|
+
return {
|
|
6728
|
+
sha: res.commit.id,
|
|
6729
|
+
type: "TAG" /* TAG */,
|
|
6730
|
+
date: res.commit.committed_date ? new Date(res.commit.committed_date) : void 0
|
|
6731
|
+
};
|
|
6732
|
+
})()
|
|
6733
|
+
]);
|
|
6734
|
+
const [branchRes, commitRes, tagRes] = results;
|
|
6735
|
+
if (tagRes.status === "fulfilled") {
|
|
6736
|
+
return tagRes.value;
|
|
6737
|
+
}
|
|
6738
|
+
if (branchRes.status === "fulfilled") {
|
|
6739
|
+
return branchRes.value;
|
|
6740
|
+
}
|
|
6741
|
+
if (commitRes.status === "fulfilled") {
|
|
6742
|
+
return commitRes.value;
|
|
6743
|
+
}
|
|
6744
|
+
throw new RefNotFoundError(`ref: ${ref} does not exist`);
|
|
6745
|
+
}
|
|
6746
|
+
function parseGitlabOwnerAndRepo(gitlabUrl) {
|
|
6747
|
+
gitlabUrl = removeTrailingSlash2(gitlabUrl);
|
|
6748
|
+
const parsingResult = parseScmURL(gitlabUrl, "GitLab" /* GitLab */);
|
|
6749
|
+
if (!parsingResult || !parsingResult.repoName) {
|
|
6750
|
+
throw new InvalidUrlPatternError(`invalid gitlab repo Url ${gitlabUrl}`);
|
|
6751
|
+
}
|
|
6752
|
+
const { organization, repoName, projectPath } = parsingResult;
|
|
6753
|
+
return { owner: organization, repo: repoName, projectPath };
|
|
6754
|
+
}
|
|
6755
|
+
async function getGitlabBlameRanges({ ref, gitlabUrl, path: path8 }, options) {
|
|
6756
|
+
const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
|
|
6757
|
+
const api2 = getGitBeaker({
|
|
6758
|
+
url: gitlabUrl,
|
|
6759
|
+
gitlabAuthToken: options?.gitlabAuthToken
|
|
6760
|
+
});
|
|
6761
|
+
const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path8, ref);
|
|
6762
|
+
let lineNumber = 1;
|
|
6763
|
+
return resp.filter((range) => range.lines).map((range) => {
|
|
6764
|
+
const oldLineNumber = lineNumber;
|
|
6765
|
+
if (!range.lines) {
|
|
6766
|
+
throw new Error("range.lines should not be undefined");
|
|
6812
6767
|
}
|
|
6813
|
-
|
|
6768
|
+
lineNumber += range.lines.length;
|
|
6769
|
+
return {
|
|
6770
|
+
startingLine: oldLineNumber,
|
|
6771
|
+
endingLine: lineNumber - 1,
|
|
6772
|
+
login: range.commit.author_email,
|
|
6773
|
+
email: range.commit.author_email,
|
|
6774
|
+
name: range.commit.author_name
|
|
6775
|
+
};
|
|
6776
|
+
});
|
|
6777
|
+
}
|
|
6778
|
+
async function processBody(response) {
|
|
6779
|
+
const headers = response.headers;
|
|
6780
|
+
const type2 = headers.get("content-type")?.split(";")[0]?.trim();
|
|
6781
|
+
if (type2 === "application/json") {
|
|
6782
|
+
return await response.json();
|
|
6783
|
+
}
|
|
6784
|
+
return await response.text();
|
|
6785
|
+
}
|
|
6786
|
+
async function brokerRequestHandler(endpoint, options) {
|
|
6787
|
+
const { prefixUrl, searchParams } = options || {};
|
|
6788
|
+
let baseUrl;
|
|
6789
|
+
if (prefixUrl) baseUrl = prefixUrl.endsWith("/") ? prefixUrl : `${prefixUrl}/`;
|
|
6790
|
+
const url = new URL(endpoint, baseUrl);
|
|
6791
|
+
url.search = searchParams || "";
|
|
6792
|
+
const dispatcher = url && isBrokerUrl(url.href) ? new ProxyAgent2({
|
|
6793
|
+
uri: GIT_PROXY_HOST,
|
|
6794
|
+
requestTls: {
|
|
6795
|
+
rejectUnauthorized: false
|
|
6796
|
+
}
|
|
6797
|
+
}) : void 0;
|
|
6798
|
+
const response = await undiciFetch(url, {
|
|
6799
|
+
headers: options?.headers,
|
|
6800
|
+
method: options?.method,
|
|
6801
|
+
body: options?.body ? String(options?.body) : void 0,
|
|
6802
|
+
dispatcher
|
|
6803
|
+
}).catch((e) => {
|
|
6804
|
+
if (e.name === "TimeoutError" || e.name === "AbortError") {
|
|
6805
|
+
throw new Error("Query timeout was reached");
|
|
6806
|
+
}
|
|
6807
|
+
throw e;
|
|
6808
|
+
});
|
|
6809
|
+
if (response.ok)
|
|
6810
|
+
return {
|
|
6811
|
+
body: await processBody(response),
|
|
6812
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
6813
|
+
status: response.status
|
|
6814
|
+
};
|
|
6815
|
+
throw new Error(`gitbeaker: ${response.statusText}`);
|
|
6814
6816
|
}
|
|
6815
6817
|
|
|
6816
|
-
// src/features/analysis/scm/
|
|
6817
|
-
var
|
|
6818
|
-
// we don't always need a url, what's important is that we have an access token
|
|
6818
|
+
// src/features/analysis/scm/gitlab/GitlabSCMLib.ts
|
|
6819
|
+
var GitlabSCMLib = class extends SCMLib {
|
|
6819
6820
|
constructor(url, accessToken, scmOrg) {
|
|
6820
6821
|
super(url, accessToken, scmOrg);
|
|
6821
|
-
__publicField(this, "githubSdk");
|
|
6822
|
-
this.githubSdk = getGithubSdk({
|
|
6823
|
-
auth: accessToken,
|
|
6824
|
-
url
|
|
6825
|
-
});
|
|
6826
6822
|
}
|
|
6827
6823
|
async createSubmitRequest(params) {
|
|
6828
6824
|
this._validateAccessTokenAndUrl();
|
|
6829
6825
|
const { targetBranchName, sourceBranchName, title, body } = params;
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
this._validateAccessToken();
|
|
6841
|
-
return this.githubSdk.forkRepo({
|
|
6842
|
-
repoUrl
|
|
6843
|
-
});
|
|
6844
|
-
}
|
|
6845
|
-
async createOrUpdateRepositorySecret(params) {
|
|
6846
|
-
this._validateAccessTokenAndUrl();
|
|
6847
|
-
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6848
|
-
const { data: repositoryPublicKeyResponse } = await this.githubSdk.getRepositoryPublicKey({ owner, repo });
|
|
6849
|
-
const { key_id, key } = repositoryPublicKeyResponse;
|
|
6850
|
-
const encryptedValue = await encryptSecret(params.value, key);
|
|
6851
|
-
return this.githubSdk.createOrUpdateRepositorySecret({
|
|
6852
|
-
encrypted_value: encryptedValue,
|
|
6853
|
-
secret_name: params.name,
|
|
6854
|
-
key_id,
|
|
6855
|
-
owner,
|
|
6856
|
-
repo
|
|
6857
|
-
});
|
|
6858
|
-
}
|
|
6859
|
-
async createPullRequestWithNewFile(sourceRepoUrl, filesPaths, userRepoUrl, title, body) {
|
|
6860
|
-
const { pull_request_url } = await this.githubSdk.createPr({
|
|
6861
|
-
sourceRepoUrl,
|
|
6862
|
-
filesPaths,
|
|
6863
|
-
userRepoUrl,
|
|
6864
|
-
title,
|
|
6865
|
-
body
|
|
6866
|
-
});
|
|
6867
|
-
return { pull_request_url };
|
|
6826
|
+
return String(
|
|
6827
|
+
await createMergeRequest({
|
|
6828
|
+
title,
|
|
6829
|
+
body,
|
|
6830
|
+
targetBranchName,
|
|
6831
|
+
sourceBranchName,
|
|
6832
|
+
repoUrl: this.url,
|
|
6833
|
+
accessToken: this.accessToken
|
|
6834
|
+
})
|
|
6835
|
+
);
|
|
6868
6836
|
}
|
|
6869
6837
|
async validateParams() {
|
|
6870
|
-
return
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
this._validateAccessTokenAndUrl();
|
|
6874
|
-
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6875
|
-
return this.githubSdk.postPrComment({
|
|
6876
|
-
...params,
|
|
6877
|
-
owner,
|
|
6878
|
-
repo
|
|
6879
|
-
});
|
|
6880
|
-
}
|
|
6881
|
-
async updatePrComment(params) {
|
|
6882
|
-
this._validateAccessTokenAndUrl();
|
|
6883
|
-
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6884
|
-
return this.githubSdk.updatePrComment({
|
|
6885
|
-
...params,
|
|
6886
|
-
owner,
|
|
6887
|
-
repo
|
|
6888
|
-
});
|
|
6889
|
-
}
|
|
6890
|
-
async deleteComment(params) {
|
|
6891
|
-
this._validateAccessTokenAndUrl();
|
|
6892
|
-
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6893
|
-
return this.githubSdk.deleteComment({
|
|
6894
|
-
...params,
|
|
6895
|
-
owner,
|
|
6896
|
-
repo
|
|
6897
|
-
});
|
|
6898
|
-
}
|
|
6899
|
-
async getPrComments(params) {
|
|
6900
|
-
this._validateAccessTokenAndUrl();
|
|
6901
|
-
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6902
|
-
return this.githubSdk.getPrComments({
|
|
6903
|
-
per_page: 100,
|
|
6904
|
-
...params,
|
|
6905
|
-
owner,
|
|
6906
|
-
repo
|
|
6907
|
-
});
|
|
6908
|
-
}
|
|
6909
|
-
async getPrDiff(params) {
|
|
6910
|
-
this._validateAccessTokenAndUrl();
|
|
6911
|
-
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
6912
|
-
const prRes = await this.githubSdk.getPrDiff({
|
|
6913
|
-
...params,
|
|
6914
|
-
owner,
|
|
6915
|
-
repo
|
|
6838
|
+
return gitlabValidateParams({
|
|
6839
|
+
url: this.url,
|
|
6840
|
+
accessToken: this.accessToken
|
|
6916
6841
|
});
|
|
6917
|
-
return z24.string().parse(prRes.data);
|
|
6918
6842
|
}
|
|
6919
6843
|
async getRepoList(_scmOrg) {
|
|
6920
|
-
this.
|
|
6921
|
-
|
|
6844
|
+
if (!this.accessToken) {
|
|
6845
|
+
console.error("no access token");
|
|
6846
|
+
throw new Error("no access token");
|
|
6847
|
+
}
|
|
6848
|
+
return getGitlabRepoList(this.url, this.accessToken);
|
|
6922
6849
|
}
|
|
6923
6850
|
async getBranchList() {
|
|
6924
6851
|
this._validateAccessTokenAndUrl();
|
|
6925
|
-
|
|
6926
|
-
|
|
6852
|
+
return getGitlabBranchList({
|
|
6853
|
+
accessToken: this.accessToken,
|
|
6854
|
+
repoUrl: this.url
|
|
6855
|
+
});
|
|
6927
6856
|
}
|
|
6928
6857
|
get scmLibType() {
|
|
6929
|
-
return "
|
|
6858
|
+
return "GITLAB" /* GITLAB */;
|
|
6930
6859
|
}
|
|
6931
6860
|
getAuthHeaders() {
|
|
6932
|
-
if (this.accessToken) {
|
|
6861
|
+
if (!this.accessToken) {
|
|
6862
|
+
return {};
|
|
6863
|
+
}
|
|
6864
|
+
if (this.accessToken.startsWith("glpat-")) {
|
|
6865
|
+
return {
|
|
6866
|
+
"Private-Token": this.accessToken
|
|
6867
|
+
};
|
|
6868
|
+
} else {
|
|
6933
6869
|
return { authorization: `Bearer ${this.accessToken}` };
|
|
6934
6870
|
}
|
|
6935
|
-
return {};
|
|
6936
6871
|
}
|
|
6937
6872
|
getDownloadUrl(sha) {
|
|
6938
|
-
this.
|
|
6939
|
-
const
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6873
|
+
const urlObj = new URL(this.url || "");
|
|
6874
|
+
const ProjectId = encodeURIComponent(
|
|
6875
|
+
urlObj.pathname.replace(/^\//, "").replace(/\/$/, "")
|
|
6876
|
+
);
|
|
6877
|
+
return Promise.resolve(
|
|
6878
|
+
//We are moving away from this form as it doesn't work when using a non-human token (group/project token)
|
|
6879
|
+
//Where as the API zip endpoint works with any token
|
|
6880
|
+
//`${this.url}/-/archive/${sha}/${repoName}-${sha}.zip`
|
|
6881
|
+
`${urlObj.origin}/api/v4/projects/${ProjectId}/repository/archive.zip?sha=${sha}`
|
|
6882
|
+
);
|
|
6946
6883
|
}
|
|
6947
6884
|
async _getUsernameForAuthUrl() {
|
|
6948
|
-
|
|
6885
|
+
if (this?.accessToken?.startsWith("glpat-")) {
|
|
6886
|
+
return this.getUsername();
|
|
6887
|
+
} else {
|
|
6888
|
+
return "oauth2";
|
|
6889
|
+
}
|
|
6949
6890
|
}
|
|
6950
6891
|
async getIsRemoteBranch(branch) {
|
|
6951
|
-
this.
|
|
6952
|
-
return
|
|
6892
|
+
this._validateAccessTokenAndUrl();
|
|
6893
|
+
return getGitlabIsRemoteBranch({
|
|
6894
|
+
accessToken: this.accessToken,
|
|
6895
|
+
repoUrl: this.url,
|
|
6896
|
+
branch
|
|
6897
|
+
});
|
|
6953
6898
|
}
|
|
6954
6899
|
async getUserHasAccessToRepo() {
|
|
6955
6900
|
this._validateAccessTokenAndUrl();
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
repoUrl: this.url
|
|
6959
|
-
username
|
|
6901
|
+
return getGitlabIsUserCollaborator({
|
|
6902
|
+
accessToken: this.accessToken,
|
|
6903
|
+
repoUrl: this.url
|
|
6960
6904
|
});
|
|
6961
6905
|
}
|
|
6962
6906
|
async getUsername() {
|
|
6963
|
-
this.
|
|
6964
|
-
return this.
|
|
6907
|
+
this._validateAccessTokenAndUrl();
|
|
6908
|
+
return getGitlabUsername(this.url, this.accessToken);
|
|
6965
6909
|
}
|
|
6966
6910
|
async getSubmitRequestStatus(scmSubmitRequestId) {
|
|
6967
6911
|
this._validateAccessTokenAndUrl();
|
|
6968
|
-
|
|
6912
|
+
const state = await getGitlabMergeRequestStatus({
|
|
6913
|
+
accessToken: this.accessToken,
|
|
6969
6914
|
repoUrl: this.url,
|
|
6970
|
-
|
|
6915
|
+
mrNumber: Number(scmSubmitRequestId)
|
|
6971
6916
|
});
|
|
6917
|
+
switch (state) {
|
|
6918
|
+
case gitlabMergeRequestStatus.merged:
|
|
6919
|
+
return "merged";
|
|
6920
|
+
case gitlabMergeRequestStatus.opened:
|
|
6921
|
+
return "open";
|
|
6922
|
+
case gitlabMergeRequestStatus.closed:
|
|
6923
|
+
return "closed";
|
|
6924
|
+
default:
|
|
6925
|
+
throw new Error(`unknown state ${state}`);
|
|
6926
|
+
}
|
|
6972
6927
|
}
|
|
6973
6928
|
async addCommentToSubmitRequest(submitRequestId, comment) {
|
|
6974
6929
|
this._validateAccessTokenAndUrl();
|
|
6975
|
-
await
|
|
6930
|
+
await createMarkdownCommentOnPullRequest({
|
|
6931
|
+
accessToken: this.accessToken,
|
|
6976
6932
|
repoUrl: this.url,
|
|
6977
|
-
|
|
6933
|
+
mrNumber: Number(submitRequestId),
|
|
6978
6934
|
markdownComment: comment
|
|
6979
6935
|
});
|
|
6980
6936
|
}
|
|
6981
6937
|
async getRepoBlameRanges(ref, path8) {
|
|
6982
6938
|
this._validateUrl();
|
|
6983
|
-
return await
|
|
6984
|
-
ref,
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6939
|
+
return await getGitlabBlameRanges(
|
|
6940
|
+
{ ref, path: path8, gitlabUrl: this.url },
|
|
6941
|
+
{
|
|
6942
|
+
url: this.url,
|
|
6943
|
+
gitlabAuthToken: this.accessToken
|
|
6944
|
+
}
|
|
6945
|
+
);
|
|
6988
6946
|
}
|
|
6989
6947
|
async getReferenceData(ref) {
|
|
6990
6948
|
this._validateUrl();
|
|
6991
|
-
return
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
owner,
|
|
6999
|
-
comment_id: commentId
|
|
7000
|
-
});
|
|
6949
|
+
return await getGitlabReferenceData(
|
|
6950
|
+
{ ref, gitlabUrl: this.url },
|
|
6951
|
+
{
|
|
6952
|
+
url: this.url,
|
|
6953
|
+
gitlabAuthToken: this.accessToken
|
|
6954
|
+
}
|
|
6955
|
+
);
|
|
7001
6956
|
}
|
|
7002
6957
|
async getRepoDefaultBranch() {
|
|
7003
6958
|
this._validateUrl();
|
|
7004
|
-
return await
|
|
6959
|
+
return await getGitlabRepoDefaultBranch(this.url, {
|
|
6960
|
+
url: this.url,
|
|
6961
|
+
gitlabAuthToken: this.accessToken
|
|
6962
|
+
});
|
|
7005
6963
|
}
|
|
7006
6964
|
async getSubmitRequestUrl(submitRequestUrl) {
|
|
7007
6965
|
this._validateAccessTokenAndUrl();
|
|
7008
|
-
const
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
pull_number: submitRequestUrl
|
|
6966
|
+
const res = await getGitlabMergeRequest({
|
|
6967
|
+
url: this.url,
|
|
6968
|
+
prNumber: submitRequestUrl,
|
|
6969
|
+
accessToken: this.accessToken
|
|
7013
6970
|
});
|
|
7014
|
-
return
|
|
6971
|
+
return res.web_url;
|
|
7015
6972
|
}
|
|
7016
6973
|
async getSubmitRequestId(submitRequestUrl) {
|
|
7017
|
-
const match = submitRequestUrl.match(/\/
|
|
6974
|
+
const match = submitRequestUrl.match(/\/merge_requests\/(\d+)/);
|
|
7018
6975
|
return match?.[1] || "";
|
|
7019
6976
|
}
|
|
7020
6977
|
async getCommitUrl(commitId) {
|
|
7021
6978
|
this._validateAccessTokenAndUrl();
|
|
7022
|
-
const
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
commitSha: commitId
|
|
6979
|
+
const res = await getGitlabCommitUrl({
|
|
6980
|
+
url: this.url,
|
|
6981
|
+
commitSha: commitId,
|
|
6982
|
+
accessToken: this.accessToken
|
|
7027
6983
|
});
|
|
7028
|
-
return
|
|
6984
|
+
return res.web_url;
|
|
7029
6985
|
}
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
});
|
|
6986
|
+
};
|
|
6987
|
+
|
|
6988
|
+
// src/features/analysis/scm/scmFactory.ts
|
|
6989
|
+
import { z as z24 } from "zod";
|
|
6990
|
+
|
|
6991
|
+
// src/features/analysis/scm/StubSCMLib.ts
|
|
6992
|
+
var StubSCMLib = class extends SCMLib {
|
|
6993
|
+
constructor(url, accessToken, scmOrg) {
|
|
6994
|
+
super(url, accessToken, scmOrg);
|
|
7040
6995
|
}
|
|
7041
|
-
async
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
7045
|
-
return await this.githubSdk.getGeneralPrComments({
|
|
7046
|
-
issue_number: prNumber,
|
|
7047
|
-
owner,
|
|
7048
|
-
repo
|
|
7049
|
-
});
|
|
6996
|
+
async getUrlWithCredentials() {
|
|
6997
|
+
console.warn("getUrlWithCredentials() returning empty string");
|
|
6998
|
+
return "";
|
|
7050
6999
|
}
|
|
7051
|
-
async
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7000
|
+
async createSubmitRequest(_params) {
|
|
7001
|
+
console.warn("createSubmitRequest() returning empty string");
|
|
7002
|
+
return "";
|
|
7003
|
+
}
|
|
7004
|
+
get scmLibType() {
|
|
7005
|
+
console.warn("scmLibType returning GITHUB as default");
|
|
7006
|
+
return "GITHUB" /* GITHUB */;
|
|
7007
|
+
}
|
|
7008
|
+
getAuthHeaders() {
|
|
7009
|
+
console.warn("getAuthHeaders() returning empty object");
|
|
7010
|
+
return {};
|
|
7011
|
+
}
|
|
7012
|
+
async getDownloadUrl(_sha) {
|
|
7013
|
+
console.warn("getDownloadUrl() returning empty string");
|
|
7014
|
+
return "";
|
|
7015
|
+
}
|
|
7016
|
+
async getIsRemoteBranch(_branch) {
|
|
7017
|
+
console.warn("getIsRemoteBranch() returning false");
|
|
7018
|
+
return false;
|
|
7019
|
+
}
|
|
7020
|
+
async validateParams() {
|
|
7021
|
+
console.warn("validateParams() no-op");
|
|
7022
|
+
}
|
|
7023
|
+
async getRepoList(_scmOrg) {
|
|
7024
|
+
console.warn("getRepoList() returning empty array");
|
|
7025
|
+
return [];
|
|
7026
|
+
}
|
|
7027
|
+
async getBranchList() {
|
|
7028
|
+
console.warn("getBranchList() returning empty array");
|
|
7029
|
+
return [];
|
|
7030
|
+
}
|
|
7031
|
+
async getUsername() {
|
|
7032
|
+
console.warn("getUsername() returning empty string");
|
|
7033
|
+
return "";
|
|
7034
|
+
}
|
|
7035
|
+
async getSubmitRequestStatus(_scmSubmitRequestId) {
|
|
7036
|
+
console.warn("getSubmitRequestStatus() returning ERROR");
|
|
7037
|
+
return "error";
|
|
7038
|
+
}
|
|
7039
|
+
async getUserHasAccessToRepo() {
|
|
7040
|
+
console.warn("getUserHasAccessToRepo() returning false");
|
|
7041
|
+
return false;
|
|
7042
|
+
}
|
|
7043
|
+
async getRepoBlameRanges(_ref, _path) {
|
|
7044
|
+
console.warn("getRepoBlameRanges() returning empty array");
|
|
7045
|
+
return [];
|
|
7046
|
+
}
|
|
7047
|
+
async getReferenceData(_ref) {
|
|
7048
|
+
console.warn("getReferenceData() returning null/empty defaults");
|
|
7049
|
+
return {
|
|
7050
|
+
type: "BRANCH" /* BRANCH */,
|
|
7051
|
+
sha: "",
|
|
7052
|
+
date: void 0
|
|
7053
|
+
};
|
|
7054
|
+
}
|
|
7055
|
+
async getRepoDefaultBranch() {
|
|
7056
|
+
console.warn("getRepoDefaultBranch() returning empty string");
|
|
7057
|
+
return "";
|
|
7058
|
+
}
|
|
7059
|
+
async getSubmitRequestUrl(_submitRequestIdNumber) {
|
|
7060
|
+
console.warn("getSubmitRequestUrl() returning empty string");
|
|
7061
|
+
return "";
|
|
7062
|
+
}
|
|
7063
|
+
async getSubmitRequestId(_submitRequestUrl) {
|
|
7064
|
+
console.warn("getSubmitRequestId() returning empty string");
|
|
7065
|
+
return "";
|
|
7066
|
+
}
|
|
7067
|
+
async getCommitUrl(_commitId) {
|
|
7068
|
+
console.warn("getCommitUrl() returning empty string");
|
|
7069
|
+
return "";
|
|
7070
|
+
}
|
|
7071
|
+
async _getUsernameForAuthUrl() {
|
|
7072
|
+
console.warn("_getUsernameForAuthUrl() returning empty string");
|
|
7073
|
+
return "";
|
|
7074
|
+
}
|
|
7075
|
+
async addCommentToSubmitRequest(_submitRequestId, _comment) {
|
|
7076
|
+
console.warn("addCommentToSubmitRequest() no-op");
|
|
7061
7077
|
}
|
|
7062
7078
|
};
|
|
7063
7079
|
|
|
7080
|
+
// src/features/analysis/scm/scmFactory.ts
|
|
7081
|
+
async function createScmLib({ url, accessToken, scmType, scmOrg }, { propagateExceptions = false } = {}) {
|
|
7082
|
+
const trimmedUrl = url ? url.trim().replace(/\/$/, "").replace(/.git$/i, "") : void 0;
|
|
7083
|
+
try {
|
|
7084
|
+
switch (scmType) {
|
|
7085
|
+
case "GITHUB" /* GITHUB */: {
|
|
7086
|
+
const scm = new GithubSCMLib(trimmedUrl, accessToken, scmOrg);
|
|
7087
|
+
await scm.validateParams();
|
|
7088
|
+
return scm;
|
|
7089
|
+
}
|
|
7090
|
+
case "GITLAB" /* GITLAB */: {
|
|
7091
|
+
const scm = new GitlabSCMLib(trimmedUrl, accessToken, scmOrg);
|
|
7092
|
+
await scm.validateParams();
|
|
7093
|
+
return scm;
|
|
7094
|
+
}
|
|
7095
|
+
case "ADO" /* ADO */: {
|
|
7096
|
+
const scm = new AdoSCMLib(trimmedUrl, accessToken, scmOrg);
|
|
7097
|
+
await scm.getAdoSdk();
|
|
7098
|
+
await scm.validateParams();
|
|
7099
|
+
return scm;
|
|
7100
|
+
}
|
|
7101
|
+
case "BITBUCKET" /* BITBUCKET */: {
|
|
7102
|
+
const scm = new BitbucketSCMLib(trimmedUrl, accessToken, scmOrg);
|
|
7103
|
+
await scm.validateParams();
|
|
7104
|
+
return scm;
|
|
7105
|
+
}
|
|
7106
|
+
}
|
|
7107
|
+
} catch (e) {
|
|
7108
|
+
if (e instanceof InvalidRepoUrlError && url) {
|
|
7109
|
+
throw new RepoNoTokenAccessError(
|
|
7110
|
+
"no access to repo",
|
|
7111
|
+
scmLibScmTypeToScmType[z24.nativeEnum(ScmLibScmType).parse(scmType)]
|
|
7112
|
+
);
|
|
7113
|
+
}
|
|
7114
|
+
console.error(`error validating scm: ${scmType} `, e);
|
|
7115
|
+
if (propagateExceptions) {
|
|
7116
|
+
throw e;
|
|
7117
|
+
}
|
|
7118
|
+
}
|
|
7119
|
+
return new StubSCMLib(trimmedUrl, void 0, void 0);
|
|
7120
|
+
}
|
|
7121
|
+
|
|
7064
7122
|
// src/features/analysis/add_fix_comments_for_pr/utils/utils.ts
|
|
7065
7123
|
import Debug7 from "debug";
|
|
7066
7124
|
import parseDiff from "parse-diff";
|
|
@@ -7235,7 +7293,8 @@ function buildIssueCommentBody({
|
|
|
7235
7293
|
projectId,
|
|
7236
7294
|
analysisId,
|
|
7237
7295
|
organizationId,
|
|
7238
|
-
irrelevantIssueWithTags
|
|
7296
|
+
irrelevantIssueWithTags,
|
|
7297
|
+
fpDescription
|
|
7239
7298
|
}) {
|
|
7240
7299
|
const issueUrl = getIssueUrlWithRedirect({
|
|
7241
7300
|
appBaseUrl: WEB_APP_URL,
|
|
@@ -7250,9 +7309,10 @@ function buildIssueCommentBody({
|
|
|
7250
7309
|
const subTitle = getCommitIssueDescription({
|
|
7251
7310
|
issueType,
|
|
7252
7311
|
vendor: scannerToVulnerability_Report_Vendor_Enum[scanner],
|
|
7253
|
-
irrelevantIssueWithTags
|
|
7312
|
+
irrelevantIssueWithTags,
|
|
7313
|
+
fpDescription
|
|
7254
7314
|
});
|
|
7255
|
-
const issuePageLink = `[Learn more
|
|
7315
|
+
const issuePageLink = `[Learn more about this issue](${issueUrl})`;
|
|
7256
7316
|
return `${title}
|
|
7257
7317
|
${subTitle}
|
|
7258
7318
|
${issuePageLink}`;
|
|
@@ -7323,7 +7383,8 @@ async function postIssueComment(params) {
|
|
|
7323
7383
|
scm,
|
|
7324
7384
|
commitSha,
|
|
7325
7385
|
pullRequest,
|
|
7326
|
-
scanner
|
|
7386
|
+
scanner,
|
|
7387
|
+
fpDescription
|
|
7327
7388
|
} = params;
|
|
7328
7389
|
const {
|
|
7329
7390
|
path: path8,
|
|
@@ -7354,7 +7415,8 @@ Refresh the page in order to see the changes.`,
|
|
|
7354
7415
|
scanner,
|
|
7355
7416
|
projectId,
|
|
7356
7417
|
analysisId,
|
|
7357
|
-
organizationId
|
|
7418
|
+
organizationId,
|
|
7419
|
+
fpDescription
|
|
7358
7420
|
});
|
|
7359
7421
|
return await scm.updatePrComment({
|
|
7360
7422
|
body: commentBody,
|
|
@@ -7567,33 +7629,49 @@ async function addFixCommentsForPr({
|
|
|
7567
7629
|
});
|
|
7568
7630
|
}
|
|
7569
7631
|
),
|
|
7570
|
-
...irrelevantVulnerabilityReportIssues.map(
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
startLine: vulnerabilityReportIssueCodeNode.startLine,
|
|
7577
|
-
vulnerabilityReportIssue: {
|
|
7578
|
-
fixId: "",
|
|
7579
|
-
safeIssueType: vulnerabilityReportIssue.safeIssueType,
|
|
7580
|
-
vulnerabilityReportIssueTags: vulnerabilityReportIssue.vulnerabilityReportIssueTags,
|
|
7581
|
-
category: vulnerabilityReportIssue.category
|
|
7582
|
-
},
|
|
7583
|
-
vulnerabilityReportIssueId: vulnerabilityReportIssue.id
|
|
7584
|
-
},
|
|
7585
|
-
projectId,
|
|
7586
|
-
analysisId,
|
|
7587
|
-
organizationId,
|
|
7588
|
-
fixesById,
|
|
7589
|
-
scm,
|
|
7590
|
-
pullRequest,
|
|
7591
|
-
scanner,
|
|
7592
|
-
commitSha
|
|
7632
|
+
...irrelevantVulnerabilityReportIssues.map(
|
|
7633
|
+
async (vulnerabilityReportIssue) => {
|
|
7634
|
+
let fpDescription = null;
|
|
7635
|
+
if (vulnerabilityReportIssue.fpId) {
|
|
7636
|
+
const fpRes = await gqlClient.getFalsePositive({
|
|
7637
|
+
fpId: vulnerabilityReportIssue.fpId
|
|
7593
7638
|
});
|
|
7639
|
+
const parsedFpRes = await FalsePositivePartsZ.parseAsync(
|
|
7640
|
+
fpRes?.getFalsePositive
|
|
7641
|
+
);
|
|
7642
|
+
const { description, contextString } = getParsedFalsePositiveMessage(parsedFpRes);
|
|
7643
|
+
fpDescription = contextString ? `${description}
|
|
7644
|
+
|
|
7645
|
+
${contextString}` : description;
|
|
7594
7646
|
}
|
|
7595
|
-
|
|
7596
|
-
|
|
7647
|
+
return vulnerabilityReportIssue.codeNodes.map(
|
|
7648
|
+
(vulnerabilityReportIssueCodeNode) => {
|
|
7649
|
+
return postIssueComment({
|
|
7650
|
+
vulnerabilityReportIssueCodeNode: {
|
|
7651
|
+
path: vulnerabilityReportIssueCodeNode.path,
|
|
7652
|
+
startLine: vulnerabilityReportIssueCodeNode.startLine,
|
|
7653
|
+
vulnerabilityReportIssue: {
|
|
7654
|
+
fixId: "",
|
|
7655
|
+
safeIssueType: vulnerabilityReportIssue.safeIssueType,
|
|
7656
|
+
vulnerabilityReportIssueTags: vulnerabilityReportIssue.vulnerabilityReportIssueTags,
|
|
7657
|
+
category: vulnerabilityReportIssue.category
|
|
7658
|
+
},
|
|
7659
|
+
vulnerabilityReportIssueId: vulnerabilityReportIssue.id
|
|
7660
|
+
},
|
|
7661
|
+
projectId,
|
|
7662
|
+
analysisId,
|
|
7663
|
+
organizationId,
|
|
7664
|
+
fixesById,
|
|
7665
|
+
scm,
|
|
7666
|
+
pullRequest,
|
|
7667
|
+
scanner,
|
|
7668
|
+
commitSha,
|
|
7669
|
+
fpDescription
|
|
7670
|
+
});
|
|
7671
|
+
}
|
|
7672
|
+
);
|
|
7673
|
+
}
|
|
7674
|
+
),
|
|
7597
7675
|
postAnalysisInsightComment({
|
|
7598
7676
|
prVulenrabilities,
|
|
7599
7677
|
pullRequest,
|
|
@@ -7699,20 +7777,24 @@ async function getGitInfo(srcDirPath) {
|
|
|
7699
7777
|
|
|
7700
7778
|
// src/features/analysis/graphql/gql.ts
|
|
7701
7779
|
import fetchOrig from "cross-fetch";
|
|
7702
|
-
import
|
|
7780
|
+
import Debug12 from "debug";
|
|
7703
7781
|
import { GraphQLClient } from "graphql-request";
|
|
7704
|
-
import { HttpProxyAgent
|
|
7782
|
+
import { HttpProxyAgent } from "http-proxy-agent";
|
|
7705
7783
|
import { HttpsProxyAgent as HttpsProxyAgent2 } from "https-proxy-agent";
|
|
7706
7784
|
import { v4 as uuidv4 } from "uuid";
|
|
7707
7785
|
|
|
7708
7786
|
// src/features/analysis/graphql/subscribe.ts
|
|
7787
|
+
import Debug11 from "debug";
|
|
7709
7788
|
import { createClient } from "graphql-ws";
|
|
7710
|
-
import { HttpProxyAgent } from "http-proxy-agent";
|
|
7711
7789
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
7712
7790
|
import WebSocket from "ws";
|
|
7791
|
+
var debug11 = Debug11("mobbdev:subscribe");
|
|
7713
7792
|
var SUBSCRIPTION_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
7714
7793
|
function createWSClient(options) {
|
|
7715
|
-
const proxy = options.url.startsWith("
|
|
7794
|
+
const proxy = options.url.startsWith("wss://") && process.env["HTTPS_PROXY"] ? new HttpsProxyAgent(process.env["HTTPS_PROXY"]) : options.url.startsWith("ws://") && process.env["HTTP_PROXY"] ? new HttpsProxyAgent(process.env["HTTP_PROXY"]) : null;
|
|
7795
|
+
debug11(
|
|
7796
|
+
`Using proxy: ${proxy ? "yes" : "no"} with url: ${options.url} and with proxy: ${process.env["HTTP_PROXY"]} for the websocket connection`
|
|
7797
|
+
);
|
|
7716
7798
|
const CustomWebSocket = class extends WebSocket {
|
|
7717
7799
|
constructor(address, protocols) {
|
|
7718
7800
|
super(address, protocols, proxy ? { agent: proxy } : void 0);
|
|
@@ -7820,6 +7902,7 @@ var VulnerabilityReportIssueNoFixCodeNodeZ = z27.object({
|
|
|
7820
7902
|
fixId: z27.string().nullable(),
|
|
7821
7903
|
category: ValidCategoriesZ,
|
|
7822
7904
|
safeIssueType: z27.string(),
|
|
7905
|
+
fpId: z27.string().uuid().nullable(),
|
|
7823
7906
|
codeNodes: z27.array(
|
|
7824
7907
|
z27.object({
|
|
7825
7908
|
path: z27.string(),
|
|
@@ -7857,7 +7940,7 @@ var GetVulByNodesMetadataZ = z27.object({
|
|
|
7857
7940
|
});
|
|
7858
7941
|
|
|
7859
7942
|
// src/features/analysis/graphql/gql.ts
|
|
7860
|
-
var
|
|
7943
|
+
var debug12 = Debug12("mobbdev:gql");
|
|
7861
7944
|
var API_KEY_HEADER_NAME = "x-mobb-key";
|
|
7862
7945
|
var REPORT_STATE_CHECK_DELAY = 5 * 1e3;
|
|
7863
7946
|
function getProxyAgent(url) {
|
|
@@ -7867,12 +7950,12 @@ function getProxyAgent(url) {
|
|
|
7867
7950
|
const isHttps = parsedUrl.protocol === "https:";
|
|
7868
7951
|
const proxy = isHttps ? HTTPS_PROXY : isHttp ? HTTP_PROXY : null;
|
|
7869
7952
|
if (proxy) {
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
return isHttps ? new HttpsProxyAgent2(proxy) : new
|
|
7953
|
+
debug12("Using proxy %s", proxy);
|
|
7954
|
+
debug12("Proxy agent %o", proxy);
|
|
7955
|
+
return isHttps ? new HttpsProxyAgent2(proxy) : new HttpProxyAgent(proxy);
|
|
7873
7956
|
}
|
|
7874
7957
|
} catch (err) {
|
|
7875
|
-
|
|
7958
|
+
debug12(`Skipping proxy for ${url}. Reason: ${err.message}`);
|
|
7876
7959
|
}
|
|
7877
7960
|
return void 0;
|
|
7878
7961
|
}
|
|
@@ -7887,7 +7970,7 @@ var fetchWithProxy = (url, options = {}) => {
|
|
|
7887
7970
|
});
|
|
7888
7971
|
}
|
|
7889
7972
|
} catch (err) {
|
|
7890
|
-
|
|
7973
|
+
debug12(`Skipping proxy for ${url}. Reason: ${err.message}`);
|
|
7891
7974
|
}
|
|
7892
7975
|
return fetchOrig(url, options);
|
|
7893
7976
|
};
|
|
@@ -7896,7 +7979,7 @@ var GQLClient = class {
|
|
|
7896
7979
|
__publicField(this, "_client");
|
|
7897
7980
|
__publicField(this, "_clientSdk");
|
|
7898
7981
|
__publicField(this, "_auth");
|
|
7899
|
-
|
|
7982
|
+
debug12(`init with ${args}`);
|
|
7900
7983
|
this._auth = args;
|
|
7901
7984
|
this._client = new GraphQLClient(API_URL, {
|
|
7902
7985
|
headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
|
|
@@ -7905,7 +7988,7 @@ var GQLClient = class {
|
|
|
7905
7988
|
fetch: fetchWithProxy,
|
|
7906
7989
|
requestMiddleware: (request) => {
|
|
7907
7990
|
const requestId = uuidv4();
|
|
7908
|
-
|
|
7991
|
+
debug12(
|
|
7909
7992
|
`sending API request with id: ${requestId} and with request: ${request.body}`
|
|
7910
7993
|
);
|
|
7911
7994
|
return {
|
|
@@ -7935,7 +8018,7 @@ var GQLClient = class {
|
|
|
7935
8018
|
await this.getUserInfo();
|
|
7936
8019
|
} catch (e) {
|
|
7937
8020
|
if (e?.toString().startsWith("FetchError")) {
|
|
7938
|
-
|
|
8021
|
+
debug12("verify connection failed %o", e);
|
|
7939
8022
|
return false;
|
|
7940
8023
|
}
|
|
7941
8024
|
}
|
|
@@ -7947,7 +8030,7 @@ var GQLClient = class {
|
|
|
7947
8030
|
try {
|
|
7948
8031
|
info = await this.getUserInfo();
|
|
7949
8032
|
} catch (e) {
|
|
7950
|
-
|
|
8033
|
+
debug12("verify token failed %o", e);
|
|
7951
8034
|
return false;
|
|
7952
8035
|
}
|
|
7953
8036
|
return info?.email || true;
|
|
@@ -7991,7 +8074,7 @@ var GQLClient = class {
|
|
|
7991
8074
|
try {
|
|
7992
8075
|
await this._clientSdk.CreateCommunityUser();
|
|
7993
8076
|
} catch (e) {
|
|
7994
|
-
|
|
8077
|
+
debug12("create community user failed %o", e);
|
|
7995
8078
|
}
|
|
7996
8079
|
}
|
|
7997
8080
|
async updateScmToken(args) {
|
|
@@ -8183,19 +8266,22 @@ var GQLClient = class {
|
|
|
8183
8266
|
async getReferenceData(args) {
|
|
8184
8267
|
return this._clientSdk.gitReference(args);
|
|
8185
8268
|
}
|
|
8269
|
+
async getFalsePositive(args) {
|
|
8270
|
+
return this._clientSdk.getFalsePositive(args);
|
|
8271
|
+
}
|
|
8186
8272
|
};
|
|
8187
8273
|
|
|
8188
8274
|
// src/features/analysis/pack.ts
|
|
8189
8275
|
import fs2 from "node:fs";
|
|
8190
8276
|
import path4 from "node:path";
|
|
8191
8277
|
import AdmZip from "adm-zip";
|
|
8192
|
-
import
|
|
8278
|
+
import Debug13 from "debug";
|
|
8193
8279
|
import { globby } from "globby";
|
|
8194
8280
|
import { isBinary } from "istextorbinary";
|
|
8195
8281
|
import { simpleGit as simpleGit3 } from "simple-git";
|
|
8196
8282
|
import { parseStringPromise } from "xml2js";
|
|
8197
8283
|
import { z as z28 } from "zod";
|
|
8198
|
-
var
|
|
8284
|
+
var debug13 = Debug13("mobbdev:pack");
|
|
8199
8285
|
var MAX_FILE_SIZE = 1024 * 1024 * 5;
|
|
8200
8286
|
var FPR_SOURCE_CODE_FILE_MAPPING_SCHEMA = z28.object({
|
|
8201
8287
|
properties: z28.object({
|
|
@@ -8218,7 +8304,7 @@ function _get_manifest_files_suffixes() {
|
|
|
8218
8304
|
return ["package.json", "pom.xml"];
|
|
8219
8305
|
}
|
|
8220
8306
|
async function pack(srcDirPath, vulnFiles) {
|
|
8221
|
-
|
|
8307
|
+
debug13("pack folder %s", srcDirPath);
|
|
8222
8308
|
let git = void 0;
|
|
8223
8309
|
try {
|
|
8224
8310
|
git = simpleGit3({
|
|
@@ -8228,13 +8314,13 @@ async function pack(srcDirPath, vulnFiles) {
|
|
|
8228
8314
|
});
|
|
8229
8315
|
await git.status();
|
|
8230
8316
|
} catch (e) {
|
|
8231
|
-
|
|
8317
|
+
debug13("failed to run git %o", e);
|
|
8232
8318
|
git = void 0;
|
|
8233
8319
|
if (e instanceof Error) {
|
|
8234
8320
|
if (e.message.includes(" spawn ")) {
|
|
8235
|
-
|
|
8321
|
+
debug13("git cli not installed");
|
|
8236
8322
|
} else if (e.message.includes("not a git repository")) {
|
|
8237
|
-
|
|
8323
|
+
debug13("folder is not a git repo");
|
|
8238
8324
|
} else {
|
|
8239
8325
|
throw e;
|
|
8240
8326
|
}
|
|
@@ -8249,9 +8335,9 @@ async function pack(srcDirPath, vulnFiles) {
|
|
|
8249
8335
|
followSymbolicLinks: false,
|
|
8250
8336
|
dot: true
|
|
8251
8337
|
});
|
|
8252
|
-
|
|
8338
|
+
debug13("files found %d", filepaths.length);
|
|
8253
8339
|
const zip = new AdmZip();
|
|
8254
|
-
|
|
8340
|
+
debug13("compressing files");
|
|
8255
8341
|
for (const filepath of filepaths) {
|
|
8256
8342
|
const absFilepath = path4.join(srcDirPath, filepath.toString());
|
|
8257
8343
|
vulnFiles = vulnFiles.concat(_get_manifest_files_suffixes());
|
|
@@ -8259,25 +8345,25 @@ async function pack(srcDirPath, vulnFiles) {
|
|
|
8259
8345
|
absFilepath.toString().replaceAll(path4.win32.sep, path4.posix.sep),
|
|
8260
8346
|
vulnFiles
|
|
8261
8347
|
)) {
|
|
8262
|
-
|
|
8348
|
+
debug13("ignoring %s because it is not a vulnerability file", filepath);
|
|
8263
8349
|
continue;
|
|
8264
8350
|
}
|
|
8265
8351
|
if (fs2.lstatSync(absFilepath).size > MAX_FILE_SIZE) {
|
|
8266
|
-
|
|
8352
|
+
debug13("ignoring %s because the size is > 5MB", filepath);
|
|
8267
8353
|
continue;
|
|
8268
8354
|
}
|
|
8269
8355
|
const data = git ? await git.showBuffer([`HEAD:./${filepath}`]) : fs2.readFileSync(absFilepath);
|
|
8270
8356
|
if (isBinary(null, data)) {
|
|
8271
|
-
|
|
8357
|
+
debug13("ignoring %s because is seems to be a binary file", filepath);
|
|
8272
8358
|
continue;
|
|
8273
8359
|
}
|
|
8274
8360
|
zip.addFile(filepath.toString(), data);
|
|
8275
8361
|
}
|
|
8276
|
-
|
|
8362
|
+
debug13("get zip file buffer");
|
|
8277
8363
|
return zip.toBuffer();
|
|
8278
8364
|
}
|
|
8279
8365
|
async function repackFpr(fprPath) {
|
|
8280
|
-
|
|
8366
|
+
debug13("repack fpr file %s", fprPath);
|
|
8281
8367
|
const zipIn = new AdmZip(fprPath);
|
|
8282
8368
|
const zipOut = new AdmZip();
|
|
8283
8369
|
const mappingXML = zipIn.readAsText("src-archive/index.xml", "utf-8");
|
|
@@ -8292,7 +8378,7 @@ async function repackFpr(fprPath) {
|
|
|
8292
8378
|
zipOut.addFile(realPath, buf);
|
|
8293
8379
|
}
|
|
8294
8380
|
}
|
|
8295
|
-
|
|
8381
|
+
debug13("get repacked zip file buffer");
|
|
8296
8382
|
return zipOut.toBuffer();
|
|
8297
8383
|
}
|
|
8298
8384
|
|
|
@@ -8369,7 +8455,7 @@ var cxOperatingSystemSupportMessage = `Your operating system does not support ch
|
|
|
8369
8455
|
|
|
8370
8456
|
// src/utils/child_process.ts
|
|
8371
8457
|
import cp from "node:child_process";
|
|
8372
|
-
import
|
|
8458
|
+
import Debug14 from "debug";
|
|
8373
8459
|
import * as process2 from "process";
|
|
8374
8460
|
import supportsColor from "supports-color";
|
|
8375
8461
|
var { stdout: stdout2 } = supportsColor;
|
|
@@ -8388,16 +8474,16 @@ function createSpwan({ args, processPath, name }, options) {
|
|
|
8388
8474
|
return createChildProcess({ childProcess: child, name }, options);
|
|
8389
8475
|
}
|
|
8390
8476
|
function createChildProcess({ childProcess, name }, options) {
|
|
8391
|
-
const
|
|
8477
|
+
const debug20 = Debug14(`mobbdev:${name}`);
|
|
8392
8478
|
const { display } = options;
|
|
8393
8479
|
return new Promise((resolve, reject) => {
|
|
8394
8480
|
let out = "";
|
|
8395
8481
|
const onData = (chunk) => {
|
|
8396
|
-
|
|
8482
|
+
debug20(`chunk received from ${name} std ${chunk}`);
|
|
8397
8483
|
out += chunk;
|
|
8398
8484
|
};
|
|
8399
8485
|
if (!childProcess || !childProcess?.stdout || !childProcess?.stderr) {
|
|
8400
|
-
|
|
8486
|
+
debug20(`unable to fork ${name}`);
|
|
8401
8487
|
reject(new Error(`unable to fork ${name}`));
|
|
8402
8488
|
}
|
|
8403
8489
|
childProcess.stdout?.on("data", onData);
|
|
@@ -8407,11 +8493,11 @@ function createChildProcess({ childProcess, name }, options) {
|
|
|
8407
8493
|
childProcess.stderr?.pipe(process2.stderr);
|
|
8408
8494
|
}
|
|
8409
8495
|
childProcess.on("exit", (code) => {
|
|
8410
|
-
|
|
8496
|
+
debug20(`${name} exit code ${code}`);
|
|
8411
8497
|
resolve({ message: out, code });
|
|
8412
8498
|
});
|
|
8413
8499
|
childProcess.on("error", (err) => {
|
|
8414
|
-
|
|
8500
|
+
debug20(`${name} error %o`, err);
|
|
8415
8501
|
reject(err);
|
|
8416
8502
|
});
|
|
8417
8503
|
});
|
|
@@ -8419,12 +8505,12 @@ function createChildProcess({ childProcess, name }, options) {
|
|
|
8419
8505
|
|
|
8420
8506
|
// src/features/analysis/scanners/checkmarx.ts
|
|
8421
8507
|
import chalk2 from "chalk";
|
|
8422
|
-
import
|
|
8508
|
+
import Debug15 from "debug";
|
|
8423
8509
|
import { existsSync } from "fs";
|
|
8424
8510
|
import { createSpinner as createSpinner2 } from "nanospinner";
|
|
8425
8511
|
import { type } from "os";
|
|
8426
8512
|
import path5 from "path";
|
|
8427
|
-
var
|
|
8513
|
+
var debug14 = Debug15("mobbdev:checkmarx");
|
|
8428
8514
|
var require2 = createRequire(import.meta.url);
|
|
8429
8515
|
var getCheckmarxPath = () => {
|
|
8430
8516
|
const os2 = type();
|
|
@@ -8465,14 +8551,14 @@ function validateCheckmarxInstallation() {
|
|
|
8465
8551
|
existsSync(getCheckmarxPath());
|
|
8466
8552
|
}
|
|
8467
8553
|
async function forkCheckmarx(args, { display }) {
|
|
8468
|
-
|
|
8554
|
+
debug14("fork checkmarx with args %o %s", args.join(" "), display);
|
|
8469
8555
|
return createSpwan(
|
|
8470
8556
|
{ args, processPath: getCheckmarxPath(), name: "checkmarx" },
|
|
8471
8557
|
{ display }
|
|
8472
8558
|
);
|
|
8473
8559
|
}
|
|
8474
8560
|
async function getCheckmarxReport({ reportPath, repositoryRoot, branch, projectName }, { skipPrompts = false }) {
|
|
8475
|
-
|
|
8561
|
+
debug14("get checkmarx report start %s %s", reportPath, repositoryRoot);
|
|
8476
8562
|
const { code: loginCode } = await forkCheckmarx(VALIDATE_COMMAND, {
|
|
8477
8563
|
display: false
|
|
8478
8564
|
});
|
|
@@ -8540,20 +8626,20 @@ async function validateCheckamxCredentials() {
|
|
|
8540
8626
|
// src/features/analysis/scanners/snyk.ts
|
|
8541
8627
|
import { createRequire as createRequire2 } from "node:module";
|
|
8542
8628
|
import chalk3 from "chalk";
|
|
8543
|
-
import
|
|
8629
|
+
import Debug16 from "debug";
|
|
8544
8630
|
import { createSpinner as createSpinner3 } from "nanospinner";
|
|
8545
8631
|
import open from "open";
|
|
8546
|
-
var
|
|
8632
|
+
var debug15 = Debug16("mobbdev:snyk");
|
|
8547
8633
|
var require3 = createRequire2(import.meta.url);
|
|
8548
8634
|
var SNYK_PATH = require3.resolve("snyk/bin/snyk");
|
|
8549
8635
|
var SNYK_ARTICLE_URL = "https://docs.snyk.io/scan-using-snyk/snyk-code/configure-snyk-code#enable-snyk-code";
|
|
8550
|
-
|
|
8636
|
+
debug15("snyk executable path %s", SNYK_PATH);
|
|
8551
8637
|
async function forkSnyk(args, { display }) {
|
|
8552
|
-
|
|
8638
|
+
debug15("fork snyk with args %o %s", args, display);
|
|
8553
8639
|
return createFork({ args, processPath: SNYK_PATH, name: "snyk" }, { display });
|
|
8554
8640
|
}
|
|
8555
8641
|
async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
8556
|
-
|
|
8642
|
+
debug15("get snyk report start %s %s", reportPath, repoRoot);
|
|
8557
8643
|
const config4 = await forkSnyk(["config"], { display: false });
|
|
8558
8644
|
const { message: configMessage } = config4;
|
|
8559
8645
|
if (!configMessage.includes("api: ")) {
|
|
@@ -8567,7 +8653,7 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
|
8567
8653
|
snykLoginSpinner.update({
|
|
8568
8654
|
text: "\u{1F513} Waiting for Snyk login to complete"
|
|
8569
8655
|
});
|
|
8570
|
-
|
|
8656
|
+
debug15("no token in the config %s", config4);
|
|
8571
8657
|
await forkSnyk(["auth"], { display: true });
|
|
8572
8658
|
snykLoginSpinner.success({ text: "\u{1F513} Login to Snyk Successful" });
|
|
8573
8659
|
}
|
|
@@ -8577,12 +8663,12 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
|
8577
8663
|
{ display: true }
|
|
8578
8664
|
);
|
|
8579
8665
|
if (scanOutput.includes("Snyk Code is not supported for org")) {
|
|
8580
|
-
|
|
8666
|
+
debug15("snyk code is not enabled %s", scanOutput);
|
|
8581
8667
|
snykSpinner.error({ text: "\u{1F50D} Snyk configuration needed" });
|
|
8582
8668
|
const answer = await snykArticlePrompt();
|
|
8583
|
-
|
|
8669
|
+
debug15("answer %s", answer);
|
|
8584
8670
|
if (answer) {
|
|
8585
|
-
|
|
8671
|
+
debug15("opening the browser");
|
|
8586
8672
|
await open(SNYK_ARTICLE_URL);
|
|
8587
8673
|
}
|
|
8588
8674
|
console.log(
|
|
@@ -8597,18 +8683,18 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
|
8597
8683
|
}
|
|
8598
8684
|
|
|
8599
8685
|
// src/features/analysis/upload-file.ts
|
|
8600
|
-
import
|
|
8686
|
+
import Debug17 from "debug";
|
|
8601
8687
|
import fetch3, { File, fileFrom, FormData } from "node-fetch";
|
|
8602
|
-
var
|
|
8688
|
+
var debug16 = Debug17("mobbdev:upload-file");
|
|
8603
8689
|
async function uploadFile({
|
|
8604
8690
|
file,
|
|
8605
8691
|
url,
|
|
8606
8692
|
uploadKey,
|
|
8607
8693
|
uploadFields
|
|
8608
8694
|
}) {
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8695
|
+
debug16("upload file start %s", url);
|
|
8696
|
+
debug16("upload fields %o", uploadFields);
|
|
8697
|
+
debug16("upload key %s", uploadKey);
|
|
8612
8698
|
const form = new FormData();
|
|
8613
8699
|
Object.entries(uploadFields).forEach(([key, value]) => {
|
|
8614
8700
|
form.append(key, value);
|
|
@@ -8617,10 +8703,10 @@ async function uploadFile({
|
|
|
8617
8703
|
form.append("key", uploadKey);
|
|
8618
8704
|
}
|
|
8619
8705
|
if (typeof file === "string") {
|
|
8620
|
-
|
|
8706
|
+
debug16("upload file from path %s", file);
|
|
8621
8707
|
form.append("file", await fileFrom(file));
|
|
8622
8708
|
} else {
|
|
8623
|
-
|
|
8709
|
+
debug16("upload file from buffer");
|
|
8624
8710
|
form.append("file", new File([file], "file"));
|
|
8625
8711
|
}
|
|
8626
8712
|
const agent = getProxyAgent(url);
|
|
@@ -8630,10 +8716,10 @@ async function uploadFile({
|
|
|
8630
8716
|
agent
|
|
8631
8717
|
});
|
|
8632
8718
|
if (!response.ok) {
|
|
8633
|
-
|
|
8719
|
+
debug16("error from S3 %s %s", response.body, response.status);
|
|
8634
8720
|
throw new Error(`Failed to upload the file: ${response.status}`);
|
|
8635
8721
|
}
|
|
8636
|
-
|
|
8722
|
+
debug16("upload file done");
|
|
8637
8723
|
}
|
|
8638
8724
|
|
|
8639
8725
|
// src/features/analysis/index.ts
|
|
@@ -8667,9 +8753,9 @@ async function downloadRepo({
|
|
|
8667
8753
|
}) {
|
|
8668
8754
|
const { createSpinner: createSpinner5 } = Spinner2({ ci });
|
|
8669
8755
|
const repoSpinner = createSpinner5("\u{1F4BE} Downloading Repo").start();
|
|
8670
|
-
|
|
8756
|
+
debug17("download repo %s %s %s", repoUrl, dirname);
|
|
8671
8757
|
const zipFilePath = path6.join(dirname, "repo.zip");
|
|
8672
|
-
|
|
8758
|
+
debug17("download URL: %s auth headers: %o", downloadUrl, authHeaders);
|
|
8673
8759
|
const response = await fetch4(downloadUrl, {
|
|
8674
8760
|
method: "GET",
|
|
8675
8761
|
headers: {
|
|
@@ -8677,7 +8763,7 @@ async function downloadRepo({
|
|
|
8677
8763
|
}
|
|
8678
8764
|
});
|
|
8679
8765
|
if (!response.ok) {
|
|
8680
|
-
|
|
8766
|
+
debug17("SCM zipball request failed %s %s", response.body, response.status);
|
|
8681
8767
|
repoSpinner.error({ text: "\u{1F4BE} Repo download failed" });
|
|
8682
8768
|
throw new Error(`Can't access ${chalk4.bold(repoUrl)}`);
|
|
8683
8769
|
}
|
|
@@ -8691,7 +8777,7 @@ async function downloadRepo({
|
|
|
8691
8777
|
if (!repoRoot) {
|
|
8692
8778
|
throw new Error("Repo root not found");
|
|
8693
8779
|
}
|
|
8694
|
-
|
|
8780
|
+
debug17("repo root %s", repoRoot);
|
|
8695
8781
|
repoSpinner.success({ text: "\u{1F4BE} Repo downloaded successfully" });
|
|
8696
8782
|
return path6.join(dirname, repoRoot);
|
|
8697
8783
|
}
|
|
@@ -8700,9 +8786,9 @@ var getReportUrl = ({
|
|
|
8700
8786
|
projectId,
|
|
8701
8787
|
fixReportId
|
|
8702
8788
|
}) => `${WEB_APP_URL}/organization/${organizationId}/project/${projectId}/report/${fixReportId}`;
|
|
8703
|
-
var
|
|
8789
|
+
var debug17 = Debug18("mobbdev:index");
|
|
8704
8790
|
var config2 = new Configstore(packageJson.name, { apiToken: "" });
|
|
8705
|
-
|
|
8791
|
+
debug17("config %o", config2);
|
|
8706
8792
|
async function runAnalysis(params, options) {
|
|
8707
8793
|
const tmpObj = tmp.dirSync({
|
|
8708
8794
|
unsafeCleanup: true
|
|
@@ -8846,7 +8932,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
8846
8932
|
commitDirectly,
|
|
8847
8933
|
pullRequest
|
|
8848
8934
|
} = params;
|
|
8849
|
-
|
|
8935
|
+
debug17("start %s %s", dirname, repo);
|
|
8850
8936
|
const { createSpinner: createSpinner5 } = Spinner2({ ci });
|
|
8851
8937
|
skipPrompts = skipPrompts || ci;
|
|
8852
8938
|
let gqlClient = new GQLClient({
|
|
@@ -8917,8 +9003,8 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
8917
9003
|
);
|
|
8918
9004
|
}
|
|
8919
9005
|
const { sha } = getReferenceDataRes.gitReference;
|
|
8920
|
-
|
|
8921
|
-
|
|
9006
|
+
debug17("project id %s", projectId);
|
|
9007
|
+
debug17("default branch %s", reference);
|
|
8922
9008
|
if (command === "scan") {
|
|
8923
9009
|
reportPath = await getReport(
|
|
8924
9010
|
{
|
|
@@ -9247,9 +9333,9 @@ async function waitForAnaysisAndReviewPr({
|
|
|
9247
9333
|
import chalk5 from "chalk";
|
|
9248
9334
|
import chalkAnimation from "chalk-animation";
|
|
9249
9335
|
import Configstore2 from "configstore";
|
|
9250
|
-
import
|
|
9336
|
+
import Debug19 from "debug";
|
|
9251
9337
|
import open3 from "open";
|
|
9252
|
-
var
|
|
9338
|
+
var debug18 = Debug19("mobbdev:commands");
|
|
9253
9339
|
async function review(params, { skipPrompts = true } = {}) {
|
|
9254
9340
|
const {
|
|
9255
9341
|
repo,
|
|
@@ -9438,9 +9524,9 @@ async function handleMobbLogin({
|
|
|
9438
9524
|
});
|
|
9439
9525
|
loginSpinner.spin();
|
|
9440
9526
|
if (encryptedApiToken) {
|
|
9441
|
-
|
|
9527
|
+
debug18("encrypted API token received %s", encryptedApiToken);
|
|
9442
9528
|
newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
|
|
9443
|
-
|
|
9529
|
+
debug18("API token decrypted");
|
|
9444
9530
|
break;
|
|
9445
9531
|
}
|
|
9446
9532
|
await sleep(LOGIN_CHECK_DELAY);
|
|
@@ -9454,7 +9540,7 @@ async function handleMobbLogin({
|
|
|
9454
9540
|
const newGqlClient = new GQLClient({ apiKey: newApiToken, type: "apiKey" });
|
|
9455
9541
|
const loginSuccess = await newGqlClient.verifyToken();
|
|
9456
9542
|
if (loginSuccess) {
|
|
9457
|
-
|
|
9543
|
+
debug18("set api token %s", newApiToken);
|
|
9458
9544
|
config3.set("apiToken", newApiToken);
|
|
9459
9545
|
loginSpinner.success({
|
|
9460
9546
|
text: `\u{1F513} Login to Mobb successful! ${typeof loginSpinner === "string" ? `Logged in as ${loginSuccess}` : ""}`
|
|
@@ -9849,13 +9935,13 @@ var parseArgs = async (args) => {
|
|
|
9849
9935
|
};
|
|
9850
9936
|
|
|
9851
9937
|
// src/index.ts
|
|
9852
|
-
var
|
|
9938
|
+
var debug19 = Debug20("mobbdev:index");
|
|
9853
9939
|
async function run() {
|
|
9854
9940
|
return parseArgs(hideBin(process.argv));
|
|
9855
9941
|
}
|
|
9856
9942
|
(async () => {
|
|
9857
9943
|
try {
|
|
9858
|
-
|
|
9944
|
+
debug19("Bugsy CLI v%s running...", packageJson.version);
|
|
9859
9945
|
await run();
|
|
9860
9946
|
process.exit(0);
|
|
9861
9947
|
} catch (err) {
|