mobbdev 1.0.67 → 1.0.75

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.
Files changed (2) hide show
  1. package/dist/index.mjs +1601 -1519
  2. package/package.json +13 -13
package/dist/index.mjs CHANGED
@@ -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";
@@ -174,9 +179,11 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
174
179
  IssueType_Enum2["RaceConditionFormatFlaw"] = "RACE_CONDITION_FORMAT_FLAW";
175
180
  IssueType_Enum2["RegexInjection"] = "REGEX_INJECTION";
176
181
  IssueType_Enum2["RegexMissingTimeout"] = "REGEX_MISSING_TIMEOUT";
182
+ IssueType_Enum2["ReturnShouldNotBeInvariant"] = "RETURN_SHOULD_NOT_BE_INVARIANT";
177
183
  IssueType_Enum2["SqlInjection"] = "SQL_Injection";
178
184
  IssueType_Enum2["Ssrf"] = "SSRF";
179
185
  IssueType_Enum2["StringFormatMisuse"] = "STRING_FORMAT_MISUSE";
186
+ IssueType_Enum2["SystemExitShouldReraise"] = "SYSTEM_EXIT_SHOULD_RERAISE";
180
187
  IssueType_Enum2["SystemInformationLeak"] = "SYSTEM_INFORMATION_LEAK";
181
188
  IssueType_Enum2["SystemInformationLeakExternal"] = "SYSTEM_INFORMATION_LEAK_EXTERNAL";
182
189
  IssueType_Enum2["TrustBoundaryViolation"] = "TRUST_BOUNDARY_VIOLATION";
@@ -459,10 +466,24 @@ var GetVulByNodesMetadataDocument = `
459
466
  vulnerabilityReportIssueTags {
460
467
  tag: vulnerability_report_issue_tag_value
461
468
  }
462
- codeNodes(order_by: {index: desc}, where: {_or: $filters}) {
469
+ codeNodes(order_by: {index: desc}, where: {_or: $filters}, limit: 1) {
463
470
  path
464
471
  startLine
465
472
  }
473
+ fpId
474
+ }
475
+ }
476
+ }
477
+ `;
478
+ var GetFalsePositiveDocument = `
479
+ query getFalsePositive($fpId: uuid!) {
480
+ getFalsePositive(fpId: $fpId) {
481
+ ... on FalsePositiveData {
482
+ extraContext {
483
+ key
484
+ value
485
+ }
486
+ fixDescription
466
487
  }
467
488
  }
468
489
  }
@@ -693,6 +714,9 @@ function getSdk(client, withWrapper = defaultWrapper) {
693
714
  getVulByNodesMetadata(variables, requestHeaders) {
694
715
  return withWrapper((wrappedRequestHeaders) => client.request(GetVulByNodesMetadataDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getVulByNodesMetadata", "query", variables);
695
716
  },
717
+ getFalsePositive(variables, requestHeaders) {
718
+ return withWrapper((wrappedRequestHeaders) => client.request(GetFalsePositiveDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getFalsePositive", "query", variables);
719
+ },
696
720
  updateScmToken(variables, requestHeaders) {
697
721
  return withWrapper((wrappedRequestHeaders) => client.request(UpdateScmTokenDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "updateScmToken", "mutation", variables);
698
722
  },
@@ -1146,7 +1170,14 @@ var issueTypeMap = {
1146
1170
  ["DUPLICATED_STRINGS" /* DuplicatedStrings */]: "String Literals Should not Be Duplicated",
1147
1171
  ["INSECURE_UUID_VERSION" /* InsecureUuidVersion */]: "Insecure UUID Version",
1148
1172
  ["GH_ACTIONS_SHELL_INJECTION" /* GhActionsShellInjection */]: "GitHub Actions Shell Injection",
1149
- ["UNSAFE_WEB_THREAD" /* UnsafeWebThread */]: "Unsafe Web Thread"
1173
+ ["MODIFIED_DEFAULT_PARAM" /* ModifiedDefaultParam */]: "Modified Default Param",
1174
+ ["UNSAFE_WEB_THREAD" /* UnsafeWebThread */]: "Unsafe Web Thread",
1175
+ ["NO_VAR" /* NoVar */]: 'Prefer "let" or "const"',
1176
+ ["INSECURE_TMP_FILE" /* InsecureTmpFile */]: "Insecure Temporary File",
1177
+ ["RETURN_SHOULD_NOT_BE_INVARIANT" /* ReturnShouldNotBeInvariant */]: "Return Should Not Be Invariant",
1178
+ ["SYSTEM_EXIT_SHOULD_RERAISE" /* SystemExitShouldReraise */]: "SystemExit Should Reraise",
1179
+ ["NO_RETURN_IN_FINALLY" /* NoReturnInFinally */]: "No Return in Finally Block",
1180
+ ["AVOID_IDENTITY_COMPARISON_CACHED_TYPES" /* AvoidIdentityComparisonCachedTypes */]: "Avoid Identity Comparison of Cached Types"
1150
1181
  };
1151
1182
  var issueTypeZ = z5.nativeEnum(IssueType_Enum);
1152
1183
  var getIssueTypeFriendlyString = (issueType) => {
@@ -1179,6 +1210,22 @@ var issueDescription = {
1179
1210
  ["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**.",
1180
1211
  ["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."
1181
1212
  };
1213
+ function replaceKeysWithValues(fixDescription, extraContext) {
1214
+ let result = fixDescription;
1215
+ extraContext.forEach(({ key, value }) => {
1216
+ result = result.replace(`\${${key}}`, value);
1217
+ });
1218
+ return result;
1219
+ }
1220
+ function getParsedFalsePositiveMessage(data) {
1221
+ const { fixDescription, extraContext } = data;
1222
+ const containsTemplate = extraContext.some(
1223
+ (context) => fixDescription.includes(`\${${context.key}}`)
1224
+ );
1225
+ const description = containsTemplate ? replaceKeysWithValues(fixDescription, extraContext) : fixDescription;
1226
+ const contextString = containsTemplate ? null : `\`\`\`${extraContext.map(({ value }) => value).join(" ")} \`\`\``;
1227
+ return { description, contextString };
1228
+ }
1182
1229
 
1183
1230
  // src/features/analysis/scm/shared/src/validations.ts
1184
1231
  var IssueTypeSettingZ = z6.object({
@@ -1260,7 +1307,9 @@ var ReportQueryResultZ = z7.object({
1260
1307
  }),
1261
1308
  fixesDoneCount: z7.number(),
1262
1309
  fixesInprogressCount: z7.number(),
1263
- fixesReadyCount: z7.number(),
1310
+ fixesReadyCount: z7.object({
1311
+ aggregate: z7.object({ count: z7.number() })
1312
+ }),
1264
1313
  issueTypes: z7.record(z7.string(), z7.number()).nullable(),
1265
1314
  issueLanguages: z7.record(z7.string(), z7.number()).nullable(),
1266
1315
  fixesCountByEffort: z7.record(z7.string(), z7.number()).nullable(),
@@ -1799,9 +1848,6 @@ import { z as z29 } from "zod";
1799
1848
  // src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
1800
1849
  import Debug8 from "debug";
1801
1850
 
1802
- // src/features/analysis/scm/github/GithubSCMLib.ts
1803
- import { z as z24 } from "zod";
1804
-
1805
1851
  // src/features/analysis/scm/errors.ts
1806
1852
  var InvalidRepoUrlError = class extends Error {
1807
1853
  constructor(m) {
@@ -1830,26 +1876,26 @@ var RepoNoTokenAccessError = class extends Error {
1830
1876
  }
1831
1877
  };
1832
1878
 
1833
- // src/features/analysis/scm/scmSubmit/index.ts
1834
- import { simpleGit } from "simple-git";
1835
- var isValidBranchName = async (branchName) => {
1836
- const git = simpleGit();
1837
- try {
1838
- const res = await git.raw(["check-ref-format", "--branch", branchName]);
1839
- if (res) {
1840
- return true;
1841
- }
1842
- return false;
1843
- } catch (e) {
1844
- return false;
1845
- }
1846
- };
1879
+ // src/features/analysis/scm/ado/constants.ts
1880
+ var DEFUALT_ADO_ORIGIN = scmCloudUrl.Ado;
1847
1881
 
1848
- // src/features/analysis/scm/types.ts
1849
- import { z as z14 } from "zod";
1882
+ // src/features/analysis/scm/ado/utils.ts
1883
+ import querystring from "node:querystring";
1884
+ import * as api from "azure-devops-node-api";
1885
+ import Debug2 from "debug";
1886
+ import { z as z18 } from "zod";
1850
1887
 
1851
- // src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
1888
+ // src/features/analysis/scm/env.ts
1852
1889
  import { z as z9 } from "zod";
1890
+ var EnvVariablesZod = z9.object({
1891
+ GITLAB_API_TOKEN: z9.string().optional(),
1892
+ GITHUB_API_TOKEN: z9.string().optional(),
1893
+ GIT_PROXY_HOST: z9.string()
1894
+ });
1895
+ var { GITLAB_API_TOKEN, GITHUB_API_TOKEN, GIT_PROXY_HOST } = EnvVariablesZod.parse(process.env);
1896
+
1897
+ // src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
1898
+ import { z as z10 } from "zod";
1853
1899
 
1854
1900
  // src/features/analysis/scm/shared/src/fixDetailsData.ts
1855
1901
  var fixDetailsData = {
@@ -2094,7 +2140,14 @@ var fixDetailsData = {
2094
2140
  ["DUPLICATED_STRINGS" /* DuplicatedStrings */]: void 0,
2095
2141
  ["INSECURE_UUID_VERSION" /* InsecureUuidVersion */]: void 0,
2096
2142
  ["GH_ACTIONS_SHELL_INJECTION" /* GhActionsShellInjection */]: void 0,
2097
- ["UNSAFE_WEB_THREAD" /* UnsafeWebThread */]: void 0
2143
+ ["MODIFIED_DEFAULT_PARAM" /* ModifiedDefaultParam */]: void 0,
2144
+ ["UNSAFE_WEB_THREAD" /* UnsafeWebThread */]: void 0,
2145
+ ["NO_VAR" /* NoVar */]: void 0,
2146
+ ["INSECURE_TMP_FILE" /* InsecureTmpFile */]: void 0,
2147
+ ["RETURN_SHOULD_NOT_BE_INVARIANT" /* ReturnShouldNotBeInvariant */]: void 0,
2148
+ ["SYSTEM_EXIT_SHOULD_RERAISE" /* SystemExitShouldReraise */]: void 0,
2149
+ ["NO_RETURN_IN_FINALLY" /* NoReturnInFinally */]: void 0,
2150
+ ["AVOID_IDENTITY_COMPARISON_CACHED_TYPES" /* AvoidIdentityComparisonCachedTypes */]: void 0
2098
2151
  };
2099
2152
 
2100
2153
  // src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
@@ -2125,7 +2178,7 @@ var getCommitDescription = ({
2125
2178
  )}**.
2126
2179
 
2127
2180
  `;
2128
- const parseIssueTypeRes = z9.nativeEnum(IssueType_Enum).safeParse(issueType);
2181
+ const parseIssueTypeRes = z10.nativeEnum(IssueType_Enum).safeParse(issueType);
2129
2182
  if (issueType && parseIssueTypeRes.success) {
2130
2183
  if (irrelevantIssueWithTags?.[0]?.tag) {
2131
2184
  description += `
@@ -2162,22 +2215,24 @@ ${guidances.map(({ guidance }) => `## Additional actions required
2162
2215
  var getCommitIssueDescription = ({
2163
2216
  vendor,
2164
2217
  issueType,
2165
- irrelevantIssueWithTags
2218
+ irrelevantIssueWithTags,
2219
+ fpDescription
2166
2220
  }) => {
2167
2221
  const issueTypeString = getIssueTypeFriendlyString(issueType);
2168
2222
  let description = `The following issues reported by ${capitalizeFirstLetter(vendor)} on this PR were found to be irrelevant to your project:
2169
2223
  `;
2170
- const parseIssueTypeRes = z9.nativeEnum(IssueType_Enum).safeParse(issueType);
2224
+ const parseIssueTypeRes = z10.nativeEnum(IssueType_Enum).safeParse(issueType);
2171
2225
  if (issueType && parseIssueTypeRes.success) {
2172
2226
  if (irrelevantIssueWithTags?.[0]?.tag) {
2173
- description += `
2227
+ description = `
2174
2228
  > [!tip]
2229
+ > The following issues reported by ${capitalizeFirstLetter(vendor)} on this PR were found to be irrelevant to your project:
2175
2230
  > ${issueTypeString} - ${lowercaseFirstLetter(getTagTooltip(irrelevantIssueWithTags[0].tag))}.
2176
2231
  > Mobb recommends to ignore this issue, however fix is available if you think differently.
2177
2232
 
2178
2233
 
2179
2234
  ## Justification
2180
- ${issueDescription[irrelevantIssueWithTags[0].tag]}
2235
+ ${fpDescription ?? issueDescription[irrelevantIssueWithTags[0].tag]}
2181
2236
  `;
2182
2237
  }
2183
2238
  const staticData = fixDetailsData[parseIssueTypeRes.data];
@@ -2191,10 +2246,10 @@ ${staticData.issueDescription}
2191
2246
  };
2192
2247
 
2193
2248
  // src/features/analysis/scm/shared/src/guidances.ts
2194
- import { z as z12 } from "zod";
2249
+ import { z as z13 } from "zod";
2195
2250
 
2196
2251
  // src/features/analysis/scm/shared/src/storedFixData/index.ts
2197
- import { z as z10 } from "zod";
2252
+ import { z as z11 } from "zod";
2198
2253
 
2199
2254
  // src/features/analysis/scm/shared/src/storedFixData/passwordInComment.ts
2200
2255
  var passwordInComment = {
@@ -2370,8 +2425,8 @@ var vulnerabilities8 = {
2370
2425
  var xml_default = vulnerabilities8;
2371
2426
 
2372
2427
  // src/features/analysis/scm/shared/src/storedFixData/index.ts
2373
- var StoredFixDataItemZ = z10.object({
2374
- guidance: z10.function().returns(z10.string())
2428
+ var StoredFixDataItemZ = z11.object({
2429
+ guidance: z11.function().returns(z11.string())
2375
2430
  });
2376
2431
  var languages = {
2377
2432
  ["Java" /* Java */]: java_default,
@@ -2385,7 +2440,7 @@ var languages = {
2385
2440
  };
2386
2441
 
2387
2442
  // src/features/analysis/scm/shared/src/storedQuestionData/index.ts
2388
- import { z as z11 } from "zod";
2443
+ import { z as z12 } from "zod";
2389
2444
 
2390
2445
  // src/features/analysis/scm/shared/src/storedQuestionData/csharp/httpOnlyCookie.ts
2391
2446
  var httpOnlyCookie = {
@@ -3584,10 +3639,10 @@ var vulnerabilities14 = {
3584
3639
  var xml_default2 = vulnerabilities14;
3585
3640
 
3586
3641
  // src/features/analysis/scm/shared/src/storedQuestionData/index.ts
3587
- var StoredQuestionDataItemZ = z11.object({
3588
- content: z11.function().args(z11.any()).returns(z11.string()),
3589
- description: z11.function().args(z11.any()).returns(z11.string()),
3590
- guidance: z11.function().args(z11.any()).returns(z11.string())
3642
+ var StoredQuestionDataItemZ = z12.object({
3643
+ content: z12.function().args(z12.any()).returns(z12.string()),
3644
+ description: z12.function().args(z12.any()).returns(z12.string()),
3645
+ guidance: z12.function().args(z12.any()).returns(z12.string())
3591
3646
  });
3592
3647
  var languages2 = {
3593
3648
  ["Java" /* Java */]: java_default2,
@@ -3682,9 +3737,9 @@ function getFixGuidances({
3682
3737
  const fixGuidance = storeFixResult.success ? [storeFixResult.data.guidance({ questions, ...extraContext })] : [];
3683
3738
  return libGuidances.concat(fixGuidance).filter((guidance) => !!guidance);
3684
3739
  }
3685
- var IssueTypeAndLanguageZ = z12.object({
3686
- issueType: z12.nativeEnum(IssueType_Enum),
3687
- issueLanguage: z12.nativeEnum(IssueLanguage_Enum)
3740
+ var IssueTypeAndLanguageZ = z13.object({
3741
+ issueType: z13.nativeEnum(IssueType_Enum),
3742
+ issueLanguage: z13.nativeEnum(IssueLanguage_Enum)
3688
3743
  });
3689
3744
  function getGuidances(args) {
3690
3745
  const safeIssueTypeAndLanguage = IssueTypeAndLanguageZ.safeParse({
@@ -3722,7 +3777,7 @@ function getGuidances(args) {
3722
3777
  }
3723
3778
 
3724
3779
  // src/features/analysis/scm/shared/src/urlParser/urlParser.ts
3725
- import { z as z13 } from "zod";
3780
+ import { z as z14 } from "zod";
3726
3781
  var ADO_PREFIX_PATH = "tfs";
3727
3782
  var NAME_REGEX = /[a-z0-9\-_.+]+/i;
3728
3783
  function detectAdoUrl(args) {
@@ -3739,7 +3794,7 @@ function detectAdoUrl(args) {
3739
3794
  scmType: "Ado" /* Ado */,
3740
3795
  organization,
3741
3796
  // project has single repo - repoName === projectName
3742
- projectName: z13.string().parse(projectName),
3797
+ projectName: z14.string().parse(projectName),
3743
3798
  repoName: projectName,
3744
3799
  prefixPath
3745
3800
  };
@@ -3750,7 +3805,7 @@ function detectAdoUrl(args) {
3750
3805
  return {
3751
3806
  scmType: "Ado" /* Ado */,
3752
3807
  organization,
3753
- projectName: z13.string().parse(projectName),
3808
+ projectName: z14.string().parse(projectName),
3754
3809
  repoName,
3755
3810
  prefixPath
3756
3811
  };
@@ -3764,7 +3819,7 @@ function detectAdoUrl(args) {
3764
3819
  scmType: "Ado" /* Ado */,
3765
3820
  organization,
3766
3821
  // project has only one repo - repoName === projectName
3767
- projectName: z13.string().parse(repoName),
3822
+ projectName: z14.string().parse(repoName),
3768
3823
  repoName,
3769
3824
  prefixPath
3770
3825
  };
@@ -3774,7 +3829,7 @@ function detectAdoUrl(args) {
3774
3829
  return {
3775
3830
  scmType: "Ado" /* Ado */,
3776
3831
  organization,
3777
- projectName: z13.string().parse(projectName),
3832
+ projectName: z14.string().parse(projectName),
3778
3833
  repoName,
3779
3834
  prefixPath
3780
3835
  };
@@ -3900,7 +3955,11 @@ function getIssueUrl({
3900
3955
  return `${appBaseUrl}/organization/${organizationId}/project/${projectId}/report/${analysisId}/issue/${issueId}`;
3901
3956
  }
3902
3957
 
3958
+ // src/features/analysis/scm/utils/index.ts
3959
+ import { z as z16 } from "zod";
3960
+
3903
3961
  // src/features/analysis/scm/types.ts
3962
+ import { z as z15 } from "zod";
3904
3963
  var ReferenceType = /* @__PURE__ */ ((ReferenceType2) => {
3905
3964
  ReferenceType2["BRANCH"] = "BRANCH";
3906
3965
  ReferenceType2["COMMIT"] = "COMMIT";
@@ -3932,14 +3991,13 @@ var scmTypeToScmLibScmType = {
3932
3991
  ["Ado" /* Ado */]: "ADO" /* ADO */,
3933
3992
  ["Bitbucket" /* Bitbucket */]: "BITBUCKET" /* BITBUCKET */
3934
3993
  };
3935
- var GetRefererenceResultZ = z14.object({
3936
- date: z14.date().optional(),
3937
- sha: z14.string(),
3938
- type: z14.nativeEnum(ReferenceType)
3994
+ var GetRefererenceResultZ = z15.object({
3995
+ date: z15.date().optional(),
3996
+ sha: z15.string(),
3997
+ type: z15.nativeEnum(ReferenceType)
3939
3998
  });
3940
3999
 
3941
4000
  // src/features/analysis/scm/utils/index.ts
3942
- import { z as z15 } from "zod";
3943
4001
  function getFixUrlWithRedirect(params) {
3944
4002
  const {
3945
4003
  fixId,
@@ -4050,7 +4108,7 @@ function shouldValidateUrl(repoUrl) {
4050
4108
  return repoUrl && isUrlHasPath(repoUrl);
4051
4109
  }
4052
4110
  function isBrokerUrl(url) {
4053
- return z15.string().uuid().safeParse(new URL(url).host).success;
4111
+ return z16.string().uuid().safeParse(new URL(url).host).success;
4054
4112
  }
4055
4113
  function buildAuthorizedRepoUrl(args) {
4056
4114
  const { url, username, password } = args;
@@ -4086,7 +4144,7 @@ function getCloudScmLibTypeFromUrl(url) {
4086
4144
  return void 0;
4087
4145
  }
4088
4146
  function getScmLibTypeFromScmType(scmType) {
4089
- const parsedScmType = z15.nativeEnum(ScmType).parse(scmType);
4147
+ const parsedScmType = z16.nativeEnum(ScmType).parse(scmType);
4090
4148
  return scmTypeToScmLibScmType[parsedScmType];
4091
4149
  }
4092
4150
  function getScmConfig({
@@ -4152,162 +4210,6 @@ function getScmConfig({
4152
4210
  };
4153
4211
  }
4154
4212
 
4155
- // src/features/analysis/scm/scm.ts
4156
- var SCMLib = class {
4157
- constructor(url, accessToken, scmOrg) {
4158
- __publicField(this, "url");
4159
- __publicField(this, "accessToken");
4160
- __publicField(this, "scmOrg");
4161
- this.accessToken = accessToken;
4162
- this.url = url;
4163
- this.scmOrg = scmOrg;
4164
- }
4165
- async getUrlWithCredentials() {
4166
- if (!this.url) {
4167
- console.error("no url for getUrlWithCredentials()");
4168
- throw new Error("no url");
4169
- }
4170
- const trimmedUrl = this.url.trim().replace(/\/$/, "");
4171
- const accessToken = this.getAccessToken();
4172
- if (!accessToken) {
4173
- return trimmedUrl;
4174
- }
4175
- if (this.scmLibType === "ADO" /* ADO */) {
4176
- const { host, protocol, pathname } = new URL(trimmedUrl);
4177
- return `${protocol}//${accessToken}@${host}${pathname}`;
4178
- }
4179
- const finalUrl = this.scmLibType === "GITLAB" /* GITLAB */ ? `${trimmedUrl}.git` : trimmedUrl;
4180
- const username = await this._getUsernameForAuthUrl();
4181
- return buildAuthorizedRepoUrl({
4182
- url: finalUrl,
4183
- username,
4184
- password: accessToken
4185
- });
4186
- }
4187
- getAccessToken() {
4188
- return this.accessToken || "";
4189
- }
4190
- getUrl() {
4191
- return this.url;
4192
- }
4193
- getName() {
4194
- if (!this.url) {
4195
- return "";
4196
- }
4197
- return this.url.split("/").at(-1) || "";
4198
- }
4199
- _validateAccessToken() {
4200
- if (!this.accessToken) {
4201
- console.error("no access token");
4202
- throw new Error("no access token");
4203
- }
4204
- }
4205
- static async getIsValidBranchName(branchName) {
4206
- return isValidBranchName(branchName);
4207
- }
4208
- _validateAccessTokenAndUrl() {
4209
- this._validateAccessToken();
4210
- this._validateUrl();
4211
- }
4212
- _validateUrl() {
4213
- if (!this.url) {
4214
- console.error("no url");
4215
- throw new InvalidRepoUrlError("no url");
4216
- }
4217
- }
4218
- };
4219
-
4220
- // src/features/analysis/scm/github/github.ts
4221
- import { RequestError } from "@octokit/request-error";
4222
-
4223
- // src/features/analysis/scm/constants.ts
4224
- var MOBB_ICON_IMG = "https://app.mobb.ai/gh-action/Logo_Rounded_Icon.svg";
4225
- var MAX_BRANCHES_FETCH = 1e3;
4226
-
4227
- // src/features/analysis/scm/github/consts.ts
4228
- var POST_COMMENT_PATH = "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments";
4229
- var DELETE_COMMENT_PATH = "DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}";
4230
- var UPDATE_COMMENT_PATH = "PATCH /repos/{owner}/{repo}/pulls/comments/{comment_id}";
4231
- var GET_PR_COMMENTS_PATH = "GET /repos/{owner}/{repo}/pulls/{pull_number}/comments";
4232
- var GET_PR_COMMENT_PATH = "GET /repos/{owner}/{repo}/pulls/comments/{comment_id}";
4233
- var REPLY_TO_CODE_REVIEW_COMMENT_PATH = "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies";
4234
- var GET_PR = "GET /repos/{owner}/{repo}/pulls/{pull_number}";
4235
- var POST_GENERAL_PR_COMMENT = "POST /repos/{owner}/{repo}/issues/{issue_number}/comments";
4236
- var GET_GENERAL_PR_COMMENTS = "GET /repos/{owner}/{repo}/issues/{issue_number}/comments";
4237
- var DELETE_GENERAL_PR_COMMENT = "DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}";
4238
- var CREATE_OR_UPDATE_A_REPOSITORY_SECRET = "PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}";
4239
- var GET_A_REPOSITORY_PUBLIC_KEY = "GET /repos/{owner}/{repo}/actions/secrets/public-key";
4240
- var GET_USER = "GET /user";
4241
- var GET_USER_REPOS = "GET /user/repos";
4242
- var GET_REPO_BRANCHES = "GET /repos/{owner}/{repo}/branches";
4243
- var GET_BLAME_DOCUMENT = `
4244
- query GetBlame(
4245
- $owner: String!
4246
- $repo: String!
4247
- $ref: String!
4248
- $path: String!
4249
- ) {
4250
- repository(name: $repo, owner: $owner) {
4251
- # branch name
4252
- object(expression: $ref) {
4253
- # cast Target to a Commit
4254
- ... on Commit {
4255
- # full repo-relative path to blame file
4256
- blame(path: $path) {
4257
- ranges {
4258
- commit {
4259
- author {
4260
- user {
4261
- name
4262
- login
4263
- }
4264
- }
4265
- authoredDate
4266
- }
4267
- startingLine
4268
- endingLine
4269
- age
4270
- }
4271
- }
4272
- }
4273
-
4274
- }
4275
- }
4276
- }
4277
- `;
4278
-
4279
- // src/features/analysis/scm/github/utils/encrypt_secret.ts
4280
- import sodium from "libsodium-wrappers";
4281
- async function encryptSecret(secret, key) {
4282
- await sodium.ready;
4283
- const binkey = sodium.from_base64(key, sodium.base64_variants.ORIGINAL);
4284
- const binsec = sodium.from_string(secret);
4285
- const encBytes = sodium.crypto_box_seal(binsec, binkey);
4286
- return sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL);
4287
- }
4288
-
4289
- // src/features/analysis/scm/github/utils/utils.ts
4290
- import { Octokit } from "octokit";
4291
- import { fetch as fetch2, ProxyAgent as ProxyAgent2 } from "undici";
4292
-
4293
- // src/features/analysis/scm/ado/constants.ts
4294
- var DEFUALT_ADO_ORIGIN = scmCloudUrl.Ado;
4295
-
4296
- // src/features/analysis/scm/ado/utils.ts
4297
- import querystring from "node:querystring";
4298
- import * as api from "azure-devops-node-api";
4299
- import Debug2 from "debug";
4300
- import { z as z18 } from "zod";
4301
-
4302
- // src/features/analysis/scm/env.ts
4303
- import { z as z16 } from "zod";
4304
- var EnvVariablesZod = z16.object({
4305
- GITLAB_API_TOKEN: z16.string().optional(),
4306
- GITHUB_API_TOKEN: z16.string().optional(),
4307
- GIT_PROXY_HOST: z16.string()
4308
- });
4309
- var { GITLAB_API_TOKEN, GITHUB_API_TOKEN, GIT_PROXY_HOST } = EnvVariablesZod.parse(process.env);
4310
-
4311
4213
  // src/features/analysis/scm/ado/validation.ts
4312
4214
  import { z as z17 } from "zod";
4313
4215
  var ValidPullRequestStatusZ = z17.union([
@@ -4918,39 +4820,121 @@ async function getAdoRepoList({
4918
4820
 
4919
4821
  // src/features/analysis/scm/ado/AdoSCMLib.ts
4920
4822
  import { setTimeout as setTimeout2 } from "node:timers/promises";
4921
- async function initAdoSdk(params) {
4922
- const { url, accessToken, scmOrg } = params;
4923
- const adoClientParams = await getAdoClientParams({
4924
- tokenOrg: scmOrg,
4925
- accessToken,
4926
- url
4927
- });
4928
- return getAdoSdk(adoClientParams);
4929
- }
4930
- var AdoSCMLib = class extends SCMLib {
4931
- constructor(url, accessToken, scmOrg) {
4932
- super(url, accessToken, scmOrg);
4933
- __publicField(this, "_adoSdkPromise");
4934
- this._adoSdkPromise = initAdoSdk({ accessToken, url, scmOrg });
4935
- }
4936
- async getAdoSdk() {
4937
- if (!this._adoSdkPromise) {
4938
- console.error("ado sdk was not initialized");
4939
- throw new InvalidAccessTokenError("ado sdk was not initialized");
4823
+
4824
+ // src/features/analysis/scm/scmSubmit/index.ts
4825
+ import { simpleGit } from "simple-git";
4826
+ var isValidBranchName = async (branchName) => {
4827
+ const git = simpleGit();
4828
+ try {
4829
+ const res = await git.raw(["check-ref-format", "--branch", branchName]);
4830
+ if (res) {
4831
+ return true;
4940
4832
  }
4941
- return this._adoSdkPromise;
4833
+ return false;
4834
+ } catch (e) {
4835
+ return false;
4942
4836
  }
4943
- async createSubmitRequest(params) {
4944
- this._validateAccessTokenAndUrl();
4945
- for (let i = 0; i < 5; i++) {
4946
- try {
4947
- const { targetBranchName, sourceBranchName, title, body } = params;
4948
- const adoSdk = await this.getAdoSdk();
4949
- const pullRequestId = await adoSdk.createAdoPullRequest({
4950
- title,
4951
- body,
4952
- targetBranchName,
4953
- sourceBranchName,
4837
+ };
4838
+
4839
+ // src/features/analysis/scm/scm.ts
4840
+ var SCMLib = class {
4841
+ constructor(url, accessToken, scmOrg) {
4842
+ __publicField(this, "url");
4843
+ __publicField(this, "accessToken");
4844
+ __publicField(this, "scmOrg");
4845
+ this.accessToken = accessToken;
4846
+ this.url = url;
4847
+ this.scmOrg = scmOrg;
4848
+ }
4849
+ async getUrlWithCredentials() {
4850
+ if (!this.url) {
4851
+ console.error("no url for getUrlWithCredentials()");
4852
+ throw new Error("no url");
4853
+ }
4854
+ const trimmedUrl = this.url.trim().replace(/\/$/, "");
4855
+ const accessToken = this.getAccessToken();
4856
+ if (!accessToken) {
4857
+ return trimmedUrl;
4858
+ }
4859
+ if (this.scmLibType === "ADO" /* ADO */) {
4860
+ const { host, protocol, pathname } = new URL(trimmedUrl);
4861
+ return `${protocol}//${accessToken}@${host}${pathname}`;
4862
+ }
4863
+ const finalUrl = this.scmLibType === "GITLAB" /* GITLAB */ ? `${trimmedUrl}.git` : trimmedUrl;
4864
+ const username = await this._getUsernameForAuthUrl();
4865
+ return buildAuthorizedRepoUrl({
4866
+ url: finalUrl,
4867
+ username,
4868
+ password: accessToken
4869
+ });
4870
+ }
4871
+ getAccessToken() {
4872
+ return this.accessToken || "";
4873
+ }
4874
+ getUrl() {
4875
+ return this.url;
4876
+ }
4877
+ getName() {
4878
+ if (!this.url) {
4879
+ return "";
4880
+ }
4881
+ return this.url.split("/").at(-1) || "";
4882
+ }
4883
+ _validateAccessToken() {
4884
+ if (!this.accessToken) {
4885
+ console.error("no access token");
4886
+ throw new Error("no access token");
4887
+ }
4888
+ }
4889
+ static async getIsValidBranchName(branchName) {
4890
+ return isValidBranchName(branchName);
4891
+ }
4892
+ _validateAccessTokenAndUrl() {
4893
+ this._validateAccessToken();
4894
+ this._validateUrl();
4895
+ }
4896
+ _validateUrl() {
4897
+ if (!this.url) {
4898
+ console.error("no url");
4899
+ throw new InvalidRepoUrlError("no url");
4900
+ }
4901
+ }
4902
+ };
4903
+
4904
+ // src/features/analysis/scm/ado/AdoSCMLib.ts
4905
+ async function initAdoSdk(params) {
4906
+ const { url, accessToken, scmOrg } = params;
4907
+ const adoClientParams = await getAdoClientParams({
4908
+ tokenOrg: scmOrg,
4909
+ accessToken,
4910
+ url
4911
+ });
4912
+ return getAdoSdk(adoClientParams);
4913
+ }
4914
+ var AdoSCMLib = class extends SCMLib {
4915
+ constructor(url, accessToken, scmOrg) {
4916
+ super(url, accessToken, scmOrg);
4917
+ __publicField(this, "_adoSdkPromise");
4918
+ this._adoSdkPromise = initAdoSdk({ accessToken, url, scmOrg });
4919
+ }
4920
+ async getAdoSdk() {
4921
+ if (!this._adoSdkPromise) {
4922
+ console.error("ado sdk was not initialized");
4923
+ throw new InvalidAccessTokenError("ado sdk was not initialized");
4924
+ }
4925
+ return this._adoSdkPromise;
4926
+ }
4927
+ async createSubmitRequest(params) {
4928
+ this._validateAccessTokenAndUrl();
4929
+ for (let i = 0; i < 5; i++) {
4930
+ try {
4931
+ const { targetBranchName, sourceBranchName, title, body } = params;
4932
+ const adoSdk = await this.getAdoSdk();
4933
+ const pullRequestId = await adoSdk.createAdoPullRequest({
4934
+ title,
4935
+ body,
4936
+ targetBranchName,
4937
+ sourceBranchName,
4954
4938
  repoUrl: this.url
4955
4939
  });
4956
4940
  return String(pullRequestId);
@@ -5662,1408 +5646,1482 @@ var BitbucketSCMLib = class extends SCMLib {
5662
5646
  }
5663
5647
  };
5664
5648
 
5665
- // src/features/analysis/scm/gitlab/gitlab.ts
5666
- import querystring3 from "node:querystring";
5667
- import {
5668
- createRequesterFn
5669
- } from "@gitbeaker/requester-utils";
5670
- import {
5671
- AccessLevel,
5672
- Gitlab
5673
- } from "@gitbeaker/rest";
5674
- import Debug4 from "debug";
5675
- import {
5676
- fetch as undiciFetch,
5677
- ProxyAgent
5678
- } from "undici";
5649
+ // src/features/analysis/scm/constants.ts
5650
+ var MOBB_ICON_IMG = "https://app.mobb.ai/gh-action/Logo_Rounded_Icon.svg";
5651
+ var MAX_BRANCHES_FETCH = 1e3;
5679
5652
 
5680
- // src/features/analysis/scm/gitlab/types.ts
5653
+ // src/features/analysis/scm/github/GithubSCMLib.ts
5681
5654
  import { z as z22 } from "zod";
5682
- var GitlabAuthResultZ = z22.object({
5683
- access_token: z22.string(),
5684
- token_type: z22.string(),
5685
- refresh_token: z22.string()
5686
- });
5687
5655
 
5688
- // src/features/analysis/scm/gitlab/gitlab.ts
5689
- var debug4 = Debug4("scm:gitlab");
5690
- function removeTrailingSlash2(str) {
5691
- return str.trim().replace(/\/+$/, "");
5656
+ // src/features/analysis/scm/github/github.ts
5657
+ import { RequestError } from "@octokit/request-error";
5658
+
5659
+ // src/features/analysis/scm/github/consts.ts
5660
+ var POST_COMMENT_PATH = "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments";
5661
+ var DELETE_COMMENT_PATH = "DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}";
5662
+ var UPDATE_COMMENT_PATH = "PATCH /repos/{owner}/{repo}/pulls/comments/{comment_id}";
5663
+ var GET_PR_COMMENTS_PATH = "GET /repos/{owner}/{repo}/pulls/{pull_number}/comments";
5664
+ var GET_PR_COMMENT_PATH = "GET /repos/{owner}/{repo}/pulls/comments/{comment_id}";
5665
+ var REPLY_TO_CODE_REVIEW_COMMENT_PATH = "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies";
5666
+ var GET_PR = "GET /repos/{owner}/{repo}/pulls/{pull_number}";
5667
+ var POST_GENERAL_PR_COMMENT = "POST /repos/{owner}/{repo}/issues/{issue_number}/comments";
5668
+ var GET_GENERAL_PR_COMMENTS = "GET /repos/{owner}/{repo}/issues/{issue_number}/comments";
5669
+ var DELETE_GENERAL_PR_COMMENT = "DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}";
5670
+ var CREATE_OR_UPDATE_A_REPOSITORY_SECRET = "PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}";
5671
+ var GET_A_REPOSITORY_PUBLIC_KEY = "GET /repos/{owner}/{repo}/actions/secrets/public-key";
5672
+ var GET_USER = "GET /user";
5673
+ var GET_USER_REPOS = "GET /user/repos";
5674
+ var GET_REPO_BRANCHES = "GET /repos/{owner}/{repo}/branches";
5675
+ var GET_BLAME_DOCUMENT = `
5676
+ query GetBlame(
5677
+ $owner: String!
5678
+ $repo: String!
5679
+ $ref: String!
5680
+ $path: String!
5681
+ ) {
5682
+ repository(name: $repo, owner: $owner) {
5683
+ # branch name
5684
+ object(expression: $ref) {
5685
+ # cast Target to a Commit
5686
+ ... on Commit {
5687
+ # full repo-relative path to blame file
5688
+ blame(path: $path) {
5689
+ ranges {
5690
+ commit {
5691
+ author {
5692
+ user {
5693
+ name
5694
+ login
5695
+ }
5696
+ }
5697
+ authoredDate
5698
+ }
5699
+ startingLine
5700
+ endingLine
5701
+ age
5702
+ }
5703
+ }
5704
+ }
5705
+
5706
+ }
5707
+ }
5708
+ }
5709
+ `;
5710
+
5711
+ // src/features/analysis/scm/github/utils/encrypt_secret.ts
5712
+ import sodium from "libsodium-wrappers";
5713
+ async function encryptSecret(secret, key) {
5714
+ await sodium.ready;
5715
+ const binkey = sodium.from_base64(key, sodium.base64_variants.ORIGINAL);
5716
+ const binsec = sodium.from_string(secret);
5717
+ const encBytes = sodium.crypto_box_seal(binsec, binkey);
5718
+ return sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL);
5692
5719
  }
5693
- function getRandomGitlabCloudAnonToken() {
5694
- if (!GITLAB_API_TOKEN || typeof GITLAB_API_TOKEN !== "string") {
5695
- return void 0;
5720
+
5721
+ // src/features/analysis/scm/github/utils/utils.ts
5722
+ import { Octokit } from "octokit";
5723
+ import { fetch as fetch2, ProxyAgent } from "undici";
5724
+ function parseGithubOwnerAndRepo(gitHubUrl) {
5725
+ gitHubUrl = normalizeUrl(gitHubUrl);
5726
+ const parsingResult = parseScmURL(gitHubUrl, "GitHub" /* GitHub */);
5727
+ if (!parsingResult) {
5728
+ throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
5696
5729
  }
5697
- const tokens = GITLAB_API_TOKEN.split(",");
5698
- return tokens[Math.floor(Math.random() * tokens.length)];
5730
+ const { organization, repoName } = parsingResult;
5731
+ if (!organization || !repoName) {
5732
+ throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
5733
+ }
5734
+ return { owner: organization, repo: repoName };
5699
5735
  }
5700
- function getGitBeaker(options) {
5701
- const token = options?.gitlabAuthToken ?? getRandomGitlabCloudAnonToken() ?? "";
5702
- const url = options.url;
5703
- const host = url ? new URL(url).origin : "https://gitlab.com";
5704
- if (token?.startsWith("glpat-") || token === "") {
5705
- return new Gitlab({
5706
- token,
5707
- host,
5708
- requesterFn: createRequesterFn(
5709
- (_, reqo) => Promise.resolve(reqo),
5710
- brokerRequestHandler
5711
- )
5736
+ function isGithubOnPrem(url) {
5737
+ if (!url) {
5738
+ return false;
5739
+ }
5740
+ return !url.includes(scmCloudUrl.GitHub);
5741
+ }
5742
+ function getFetch(url) {
5743
+ if (url && isBrokerUrl(url)) {
5744
+ const dispatcher = new ProxyAgent({
5745
+ uri: GIT_PROXY_HOST,
5746
+ requestTls: {
5747
+ rejectUnauthorized: false
5748
+ }
5712
5749
  });
5750
+ return (input, init) => {
5751
+ return fetch2(input, {
5752
+ ...init,
5753
+ dispatcher
5754
+ });
5755
+ };
5713
5756
  }
5714
- return new Gitlab({
5715
- oauthToken: token,
5716
- host,
5717
- requesterFn: createRequesterFn(
5718
- (_, reqo) => Promise.resolve(reqo),
5719
- brokerRequestHandler
5720
- )
5721
- });
5757
+ return fetch2;
5722
5758
  }
5723
- async function gitlabValidateParams({
5724
- url,
5725
- accessToken
5726
- }) {
5727
- try {
5728
- const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
5729
- if (accessToken) {
5730
- await api2.Users.showCurrentUser();
5731
- }
5732
- if (url && shouldValidateUrl(url)) {
5733
- const { projectPath } = parseGitlabOwnerAndRepo(url);
5734
- await api2.Projects.show(projectPath);
5759
+ function getRandomGithubCloudAnonToken() {
5760
+ if (!GITHUB_API_TOKEN || typeof GITHUB_API_TOKEN !== "string") {
5761
+ return void 0;
5762
+ }
5763
+ const tokens = GITHUB_API_TOKEN.split(",");
5764
+ return tokens[Math.floor(Math.random() * tokens.length)];
5765
+ }
5766
+ function getOctoKit(options) {
5767
+ const token = !options?.auth && !isGithubOnPrem(options?.url) ? getRandomGithubCloudAnonToken() : options?.auth;
5768
+ const baseUrl = options?.url && isGithubOnPrem(options.url) ? `${new URL(options.url).origin}/api/v3` : void 0;
5769
+ return new Octokit({
5770
+ ...options,
5771
+ auth: token,
5772
+ baseUrl,
5773
+ //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
5774
+ //to debug the performance of these API calls.
5775
+ log: GITHUB_API_TOKEN ? console : void 0,
5776
+ request: {
5777
+ fetch: getFetch(baseUrl)
5778
+ },
5779
+ retry: {
5780
+ enabled: false
5781
+ },
5782
+ throttle: {
5783
+ enabled: false
5784
+ }
5785
+ });
5786
+ }
5787
+ function isGithubActionActionToken(token) {
5788
+ return token.startsWith("ghs_");
5789
+ }
5790
+ async function githubValidateParams(url, accessToken) {
5791
+ try {
5792
+ const oktoKit = getOctoKit({ auth: accessToken, url });
5793
+ if (accessToken && !isGithubActionActionToken(accessToken)) {
5794
+ await oktoKit.rest.users.getAuthenticated();
5795
+ }
5796
+ if (url && shouldValidateUrl(url)) {
5797
+ const { owner, repo } = parseGithubOwnerAndRepo(url);
5798
+ await oktoKit.request(GET_REPO_BRANCHES, {
5799
+ owner,
5800
+ repo,
5801
+ per_page: 1
5802
+ });
5735
5803
  }
5736
5804
  } catch (e) {
5805
+ console.log("could not init github scm", e);
5737
5806
  const error = e;
5738
- const code = error.code || error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
5739
- const description = error.description || `${e}`;
5740
- if (code === 401 || code === 403 || description.includes("401") || description.includes("403")) {
5741
- throw new InvalidAccessTokenError(`invalid gitlab access token`);
5807
+ const code = error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
5808
+ if (code === 401 || code === 403) {
5809
+ throw new InvalidAccessTokenError(`invalid github access token`);
5742
5810
  }
5743
- if (code === 404 || description.includes("404") || description.includes("Not Found")) {
5744
- throw new InvalidRepoUrlError(`invalid gitlab repo URL: ${url}`);
5811
+ if (code === 404) {
5812
+ throw new InvalidRepoUrlError(`invalid github repo Url ${url}`);
5745
5813
  }
5746
- console.log("gitlabValidateParams error", e);
5814
+ console.log("githubValidateParams error", e);
5747
5815
  throw new InvalidRepoUrlError(
5748
- `cannot access gitlab repo URL: ${url} with the provided access token`
5816
+ `cannot access GH repo URL: ${url} with the provided access token`
5749
5817
  );
5750
5818
  }
5751
5819
  }
5752
- async function getGitlabUsername(url, accessToken) {
5753
- const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
5754
- const res = await api2.Users.showCurrentUser();
5755
- return res.username;
5756
- }
5757
- async function getGitlabIsUserCollaborator({
5758
- accessToken,
5759
- repoUrl
5760
- }) {
5761
- try {
5762
- const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
5763
- const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
5764
- const proj = await api2.Projects.show(projectPath);
5765
- const groupAccess = proj.permissions?.group_access?.access_level || 0;
5766
- const projectAccess = proj.permissions?.project_access?.access_level || 0;
5767
- const accessLevelWithWriteAccess = [
5768
- AccessLevel.DEVELOPER,
5769
- AccessLevel.MAINTAINER,
5770
- AccessLevel.OWNER,
5771
- AccessLevel.ADMIN
5772
- ];
5773
- return accessLevelWithWriteAccess.includes(groupAccess) || accessLevelWithWriteAccess.includes(projectAccess);
5774
- } catch (e) {
5775
- return false;
5776
- }
5777
- }
5778
- var gitlabMergeRequestStatus = {
5779
- merged: "merged",
5780
- opened: "opened",
5781
- closed: "closed"
5782
- };
5783
- async function getGitlabMergeRequestStatus({
5784
- accessToken,
5785
- repoUrl,
5786
- mrNumber
5787
- }) {
5788
- const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
5789
- const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
5790
- const res = await api2.MergeRequests.show(projectPath, mrNumber);
5791
- switch (res.state) {
5792
- case gitlabMergeRequestStatus.merged:
5793
- case gitlabMergeRequestStatus.opened:
5794
- case gitlabMergeRequestStatus.closed:
5795
- return res.state;
5796
- default:
5797
- throw new Error(`unknown merge request state ${res.state}`);
5798
- }
5799
- }
5800
- async function createMarkdownCommentOnPullRequest({
5801
- markdownComment,
5802
- accessToken,
5803
- repoUrl,
5804
- mrNumber
5805
- }) {
5806
- const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
5807
- const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
5808
- return api2.MergeRequestNotes.create(projectPath, mrNumber, markdownComment);
5809
- }
5810
- async function getGitlabIsRemoteBranch({
5811
- accessToken,
5812
- repoUrl,
5813
- branch
5814
- }) {
5815
- const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
5816
- const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
5817
- try {
5818
- const res = await api2.Branches.show(projectPath, branch);
5819
- return res.name === branch;
5820
- } catch (e) {
5821
- return false;
5822
- }
5823
- }
5824
- async function getGitlabRepoList(url, accessToken) {
5825
- const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
5826
- const res = await api2.Projects.all({
5827
- membership: true,
5828
- //TODO: a bug in the sorting mechanism of this api call
5829
- //disallows us to sort by updated_at in descending order
5830
- //so we have to sort by updated_at in ascending order.
5831
- //We can wait for the bug to be fixed or call the api
5832
- //directly with fetch()
5833
- sort: "asc",
5834
- orderBy: "updated_at",
5835
- perPage: 100
5836
- });
5837
- return Promise.all(
5838
- res.map(async (project) => {
5839
- const proj = await api2.Projects.show(project.id);
5840
- const owner = proj.namespace.name;
5841
- const repoLanguages = await api2.Projects.showLanguages(project.id);
5842
- return {
5843
- repoName: project.path,
5844
- repoUrl: project.web_url,
5845
- repoOwner: owner,
5846
- repoLanguages: Object.keys(repoLanguages),
5847
- repoIsPublic: project.visibility === "public",
5848
- repoUpdatedAt: project.last_activity_at
5849
- };
5850
- })
5851
- );
5852
- }
5853
- async function getGitlabBranchList({
5854
- accessToken,
5855
- repoUrl
5856
- }) {
5857
- const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
5858
- const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
5859
- try {
5860
- const res = await api2.Branches.all(projectPath, {
5861
- //keyset API pagination is not supported by GL for the branch list (at least not the on-prem version)
5862
- //so for now we stick with the default pagination and just return the first page and limit the results to 1000 entries.
5863
- //This is a temporary solution until we implement list branches with name search.
5864
- perPage: MAX_BRANCHES_FETCH,
5865
- page: 1
5866
- });
5867
- res.sort((a, b) => {
5868
- if (!a.commit?.committed_date || !b.commit?.committed_date) {
5869
- return 0;
5820
+
5821
+ // src/features/analysis/scm/github/github.ts
5822
+ function getGithubSdk(params = {}) {
5823
+ const octokit = getOctoKit(params);
5824
+ return {
5825
+ async postPrComment(params2) {
5826
+ return octokit.request(POST_COMMENT_PATH, params2);
5827
+ },
5828
+ async updatePrComment(params2) {
5829
+ return octokit.request(UPDATE_COMMENT_PATH, params2);
5830
+ },
5831
+ async getPrComments(params2) {
5832
+ return octokit.request(GET_PR_COMMENTS_PATH, params2);
5833
+ },
5834
+ async getPrComment(params2) {
5835
+ return octokit.request(GET_PR_COMMENT_PATH, params2);
5836
+ },
5837
+ async deleteComment(params2) {
5838
+ return octokit.request(DELETE_COMMENT_PATH, params2);
5839
+ },
5840
+ async replyToCodeReviewComment(params2) {
5841
+ return octokit.request(REPLY_TO_CODE_REVIEW_COMMENT_PATH, params2);
5842
+ },
5843
+ async getPrDiff(params2) {
5844
+ return octokit.request(GET_PR, {
5845
+ ...params2,
5846
+ mediaType: { format: "diff" }
5847
+ });
5848
+ },
5849
+ async getPr(params2) {
5850
+ return octokit.request(GET_PR, { ...params2 });
5851
+ },
5852
+ async createOrUpdateRepositorySecret(params2) {
5853
+ return octokit.request(CREATE_OR_UPDATE_A_REPOSITORY_SECRET, params2);
5854
+ },
5855
+ async getRepositoryPublicKey(params2) {
5856
+ return octokit.request(GET_A_REPOSITORY_PUBLIC_KEY, params2);
5857
+ },
5858
+ async postGeneralPrComment(params2) {
5859
+ return octokit.request(POST_GENERAL_PR_COMMENT, params2);
5860
+ },
5861
+ async getGeneralPrComments(params2) {
5862
+ return octokit.request(GET_GENERAL_PR_COMMENTS, params2);
5863
+ },
5864
+ async deleteGeneralPrComment(params2) {
5865
+ return octokit.request(DELETE_GENERAL_PR_COMMENT, params2);
5866
+ },
5867
+ async getGithubUsername() {
5868
+ const res = await octokit.rest.users.getAuthenticated();
5869
+ return res.data.login;
5870
+ },
5871
+ async getGithubIsUserCollaborator(params2) {
5872
+ const { username, repoUrl } = params2;
5873
+ try {
5874
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
5875
+ const res = await octokit.rest.repos.checkCollaborator({
5876
+ owner,
5877
+ repo,
5878
+ username
5879
+ });
5880
+ if (res.status === 204) {
5881
+ return true;
5882
+ }
5883
+ } catch (e) {
5884
+ return false;
5870
5885
  }
5871
- return new Date(b.commit?.committed_date).getTime() - new Date(a.commit?.committed_date).getTime();
5872
- });
5873
- return res.map((branch) => branch.name).slice(0, MAX_BRANCHES_FETCH);
5874
- } catch (e) {
5875
- return [];
5876
- }
5877
- }
5878
- async function createMergeRequest(options) {
5879
- const { projectPath } = parseGitlabOwnerAndRepo(options.repoUrl);
5880
- const api2 = getGitBeaker({
5881
- url: options.repoUrl,
5882
- gitlabAuthToken: options.accessToken
5883
- });
5884
- const res = await api2.MergeRequests.create(
5885
- projectPath,
5886
- options.sourceBranchName,
5887
- options.targetBranchName,
5888
- options.title,
5889
- {
5890
- description: options.body
5891
- }
5892
- );
5893
- return res.iid;
5894
- }
5895
- async function getGitlabMergeRequest({
5896
- url,
5897
- prNumber,
5898
- accessToken
5899
- }) {
5900
- const { projectPath } = parseGitlabOwnerAndRepo(url);
5901
- const api2 = getGitBeaker({
5902
- url,
5903
- gitlabAuthToken: accessToken
5904
- });
5905
- return await api2.MergeRequests.show(projectPath, prNumber);
5906
- }
5907
- async function getGitlabCommitUrl({
5908
- url,
5909
- commitSha,
5910
- accessToken
5911
- }) {
5912
- const { projectPath } = parseGitlabOwnerAndRepo(url);
5913
- const api2 = getGitBeaker({
5914
- url,
5915
- gitlabAuthToken: accessToken
5916
- });
5917
- return await api2.Commits.show(projectPath, commitSha);
5918
- }
5919
- async function getGitlabRepoDefaultBranch(repoUrl, options) {
5920
- const api2 = getGitBeaker({
5921
- url: repoUrl,
5922
- gitlabAuthToken: options?.gitlabAuthToken
5923
- });
5924
- const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
5925
- const project = await api2.Projects.show(projectPath);
5926
- if (!project.default_branch) {
5927
- throw new Error("no default branch");
5928
- }
5929
- return project.default_branch;
5930
- }
5931
- async function getGitlabReferenceData({ ref, gitlabUrl }, options) {
5932
- const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
5933
- const api2 = getGitBeaker({
5934
- url: gitlabUrl,
5935
- gitlabAuthToken: options?.gitlabAuthToken
5936
- });
5937
- const results = await Promise.allSettled([
5938
- (async () => {
5939
- const res = await api2.Branches.show(projectPath, ref);
5940
- return {
5941
- sha: res.commit.id,
5942
- type: "BRANCH" /* BRANCH */,
5943
- date: res.commit.committed_date ? new Date(res.commit.committed_date) : void 0
5944
- };
5945
- })(),
5946
- (async () => {
5947
- const res = await api2.Commits.show(projectPath, ref);
5948
- return {
5949
- sha: res.id,
5950
- type: "COMMIT" /* COMMIT */,
5951
- date: res.committed_date ? new Date(res.committed_date) : void 0
5952
- };
5953
- })(),
5954
- (async () => {
5955
- const res = await api2.Tags.show(projectPath, ref);
5886
+ return false;
5887
+ },
5888
+ async getGithubPullRequestStatus(params2) {
5889
+ const { repoUrl, prNumber } = params2;
5890
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
5891
+ const res = await octokit.rest.pulls.get({
5892
+ owner,
5893
+ repo,
5894
+ pull_number: prNumber
5895
+ });
5896
+ if (res.data.merged) {
5897
+ return "merged";
5898
+ }
5899
+ if (res.data.draft) {
5900
+ return "draft";
5901
+ }
5902
+ return res.data.state;
5903
+ },
5904
+ async createMarkdownCommentOnPullRequest(params2) {
5905
+ const { repoUrl, prNumber, markdownComment } = params2;
5906
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
5907
+ return octokit.rest.issues.createComment({
5908
+ owner,
5909
+ repo,
5910
+ issue_number: prNumber,
5911
+ body: markdownComment
5912
+ });
5913
+ },
5914
+ async getGithubIsRemoteBranch(params2) {
5915
+ const { repoUrl, branch } = params2;
5916
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
5917
+ try {
5918
+ const res = await octokit.rest.repos.getBranch({
5919
+ owner,
5920
+ repo,
5921
+ branch
5922
+ });
5923
+ return branch === res.data.name;
5924
+ } catch (e) {
5925
+ return false;
5926
+ }
5927
+ },
5928
+ async getGithubRepoList() {
5929
+ try {
5930
+ const githubRepos = await octokit.request(GET_USER_REPOS, {
5931
+ sort: "updated"
5932
+ });
5933
+ return githubRepos.data.map((repo) => ({
5934
+ repoName: repo.name,
5935
+ repoUrl: repo.html_url,
5936
+ repoOwner: repo.owner.login,
5937
+ repoLanguages: repo.language ? [repo.language] : [],
5938
+ repoIsPublic: !repo.private,
5939
+ repoUpdatedAt: repo.updated_at
5940
+ }));
5941
+ } catch (e) {
5942
+ if (e instanceof RequestError && e.status === 401) {
5943
+ return [];
5944
+ }
5945
+ if (e instanceof RequestError && e.status === 404) {
5946
+ return [];
5947
+ }
5948
+ throw e;
5949
+ }
5950
+ },
5951
+ async getGithubRepoDefaultBranch(repoUrl) {
5952
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
5953
+ const repos = await octokit.rest.repos.get({ repo, owner });
5954
+ return repos.data.default_branch;
5955
+ },
5956
+ async getGithubReferenceData({
5957
+ ref,
5958
+ gitHubUrl
5959
+ }) {
5960
+ const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
5961
+ let res;
5962
+ try {
5963
+ res = await Promise.any([
5964
+ this.getBranch({ owner, repo, branch: ref }).then((result) => ({
5965
+ date: result.data.commit.commit.committer?.date ? new Date(result.data.commit.commit.committer?.date) : void 0,
5966
+ type: "BRANCH" /* BRANCH */,
5967
+ sha: result.data.commit.sha
5968
+ })),
5969
+ this.getCommit({ commitSha: ref, repo, owner }).then((commit) => ({
5970
+ date: new Date(commit.data.committer.date),
5971
+ type: "COMMIT" /* COMMIT */,
5972
+ sha: commit.data.sha
5973
+ })),
5974
+ this.getTagDate({ owner, repo, tag: ref }).then((data) => ({
5975
+ date: new Date(data.date),
5976
+ type: "TAG" /* TAG */,
5977
+ sha: data.sha
5978
+ }))
5979
+ ]);
5980
+ return res;
5981
+ } catch (e) {
5982
+ if (e instanceof AggregateError) {
5983
+ throw new RefNotFoundError(`ref: ${ref} does not exist`);
5984
+ }
5985
+ throw e;
5986
+ }
5987
+ },
5988
+ async getBranch({
5989
+ branch,
5990
+ owner,
5991
+ repo
5992
+ }) {
5993
+ return octokit.rest.repos.getBranch({
5994
+ branch,
5995
+ owner,
5996
+ repo
5997
+ });
5998
+ },
5999
+ async getCommit({
6000
+ commitSha,
6001
+ owner,
6002
+ repo
6003
+ }) {
6004
+ return octokit.rest.git.getCommit({
6005
+ repo,
6006
+ owner,
6007
+ commit_sha: commitSha
6008
+ });
6009
+ },
6010
+ async getTagDate({
6011
+ tag,
6012
+ owner,
6013
+ repo
6014
+ }) {
6015
+ const refResponse = await octokit.rest.git.getRef({
6016
+ ref: `tags/${tag}`,
6017
+ owner,
6018
+ repo
6019
+ });
6020
+ const tagSha = refResponse.data.object.sha;
6021
+ if (refResponse.data.object.type === "commit") {
6022
+ const res2 = await octokit.rest.git.getCommit({
6023
+ commit_sha: tagSha,
6024
+ owner,
6025
+ repo
6026
+ });
6027
+ return {
6028
+ date: res2.data.committer.date,
6029
+ sha: res2.data.sha
6030
+ };
6031
+ }
6032
+ const res = await octokit.rest.git.getTag({
6033
+ tag_sha: tagSha,
6034
+ owner,
6035
+ repo
6036
+ });
5956
6037
  return {
5957
- sha: res.commit.id,
5958
- type: "TAG" /* TAG */,
5959
- date: res.commit.committed_date ? new Date(res.commit.committed_date) : void 0
6038
+ date: res.data.tagger.date,
6039
+ sha: res.data.sha
5960
6040
  };
5961
- })()
5962
- ]);
5963
- const [branchRes, commitRes, tagRes] = results;
5964
- if (tagRes.status === "fulfilled") {
5965
- return tagRes.value;
5966
- }
5967
- if (branchRes.status === "fulfilled") {
5968
- return branchRes.value;
5969
- }
5970
- if (commitRes.status === "fulfilled") {
5971
- return commitRes.value;
5972
- }
5973
- throw new RefNotFoundError(`ref: ${ref} does not exist`);
5974
- }
5975
- function parseGitlabOwnerAndRepo(gitlabUrl) {
5976
- gitlabUrl = removeTrailingSlash2(gitlabUrl);
5977
- const parsingResult = parseScmURL(gitlabUrl, "GitLab" /* GitLab */);
5978
- if (!parsingResult || !parsingResult.repoName) {
5979
- throw new InvalidUrlPatternError(`invalid gitlab repo Url ${gitlabUrl}`);
5980
- }
5981
- const { organization, repoName, projectPath } = parsingResult;
5982
- return { owner: organization, repo: repoName, projectPath };
5983
- }
5984
- async function getGitlabBlameRanges({ ref, gitlabUrl, path: path8 }, options) {
5985
- const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
5986
- const api2 = getGitBeaker({
5987
- url: gitlabUrl,
5988
- gitlabAuthToken: options?.gitlabAuthToken
5989
- });
5990
- const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path8, ref);
5991
- let lineNumber = 1;
5992
- return resp.filter((range) => range.lines).map((range) => {
5993
- const oldLineNumber = lineNumber;
5994
- if (!range.lines) {
5995
- throw new Error("range.lines should not be undefined");
5996
- }
5997
- lineNumber += range.lines.length;
5998
- return {
5999
- startingLine: oldLineNumber,
6000
- endingLine: lineNumber - 1,
6001
- login: range.commit.author_email,
6002
- email: range.commit.author_email,
6003
- name: range.commit.author_name
6004
- };
6005
- });
6006
- }
6007
- async function processBody(response) {
6008
- const headers = response.headers;
6009
- const type2 = headers.get("content-type")?.split(";")[0]?.trim();
6010
- if (type2 === "application/json") {
6011
- return await response.json();
6012
- }
6013
- return await response.text();
6014
- }
6015
- async function brokerRequestHandler(endpoint, options) {
6016
- const { prefixUrl, searchParams } = options || {};
6017
- let baseUrl;
6018
- if (prefixUrl) baseUrl = prefixUrl.endsWith("/") ? prefixUrl : `${prefixUrl}/`;
6019
- const url = new URL(endpoint, baseUrl);
6020
- url.search = searchParams || "";
6021
- const dispatcher = url && isBrokerUrl(url.href) ? new ProxyAgent({
6022
- uri: GIT_PROXY_HOST,
6023
- requestTls: {
6024
- rejectUnauthorized: false
6025
- }
6026
- }) : void 0;
6027
- const response = await undiciFetch(url, {
6028
- headers: options?.headers,
6029
- method: options?.method,
6030
- body: options?.body ? String(options?.body) : void 0,
6031
- dispatcher
6032
- }).catch((e) => {
6033
- if (e.name === "TimeoutError" || e.name === "AbortError") {
6034
- throw new Error("Query timeout was reached");
6041
+ },
6042
+ async getGithubBlameRanges(params2) {
6043
+ const { ref, gitHubUrl, path: path8 } = params2;
6044
+ const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
6045
+ const res = await octokit.graphql(
6046
+ GET_BLAME_DOCUMENT,
6047
+ {
6048
+ owner,
6049
+ repo,
6050
+ path: path8,
6051
+ ref
6052
+ }
6053
+ );
6054
+ if (!res?.repository?.object?.blame?.ranges) {
6055
+ return [];
6056
+ }
6057
+ return res.repository.object.blame.ranges.map((range) => ({
6058
+ startingLine: range.startingLine,
6059
+ endingLine: range.endingLine,
6060
+ email: range.commit.author.user?.email || "",
6061
+ name: range.commit.author.user?.name || "",
6062
+ login: range.commit.author.user?.login || ""
6063
+ }));
6064
+ },
6065
+ // todo: refactor the name for this function
6066
+ async createPr(params2) {
6067
+ const { sourceRepoUrl, filesPaths, userRepoUrl, title, body } = params2;
6068
+ const { owner: sourceOwner, repo: sourceRepo } = parseGithubOwnerAndRepo(sourceRepoUrl);
6069
+ const { owner, repo } = parseGithubOwnerAndRepo(userRepoUrl);
6070
+ const [sourceFilePath, secondFilePath] = filesPaths;
6071
+ const sourceFileContentResponse = await octokit.rest.repos.getContent({
6072
+ owner: sourceOwner,
6073
+ repo: sourceRepo,
6074
+ path: "/" + sourceFilePath
6075
+ });
6076
+ const { data: repository } = await octokit.rest.repos.get({ owner, repo });
6077
+ const defaultBranch = repository.default_branch;
6078
+ const newBranchName = `mobb/workflow-${Date.now()}`;
6079
+ await octokit.rest.git.createRef({
6080
+ owner,
6081
+ repo,
6082
+ ref: `refs/heads/${newBranchName}`,
6083
+ sha: await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha)
6084
+ });
6085
+ const decodedContent = Buffer.from(
6086
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6087
+ // @ts-ignore
6088
+ sourceFileContentResponse.data.content,
6089
+ "base64"
6090
+ ).toString("utf-8");
6091
+ const tree = [
6092
+ {
6093
+ path: sourceFilePath,
6094
+ mode: "100644",
6095
+ type: "blob",
6096
+ content: decodedContent
6097
+ }
6098
+ ];
6099
+ if (secondFilePath) {
6100
+ const secondFileContentResponse = await octokit.rest.repos.getContent({
6101
+ owner: sourceOwner,
6102
+ repo: sourceRepo,
6103
+ path: "/" + secondFilePath
6104
+ });
6105
+ const secondDecodedContent = Buffer.from(
6106
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6107
+ // @ts-ignore
6108
+ secondFileContentResponse.data.content,
6109
+ "base64"
6110
+ ).toString("utf-8");
6111
+ tree.push({
6112
+ path: secondFilePath,
6113
+ mode: "100644",
6114
+ type: "blob",
6115
+ content: secondDecodedContent
6116
+ });
6117
+ }
6118
+ const createTreeResponse = await octokit.rest.git.createTree({
6119
+ owner,
6120
+ repo,
6121
+ base_tree: await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha),
6122
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6123
+ // @ts-ignore
6124
+ tree
6125
+ });
6126
+ const createCommitResponse = await octokit.rest.git.createCommit({
6127
+ owner,
6128
+ repo,
6129
+ message: "Add new yaml file",
6130
+ tree: createTreeResponse.data.sha,
6131
+ parents: [
6132
+ await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha)
6133
+ ]
6134
+ });
6135
+ await octokit.rest.git.updateRef({
6136
+ owner,
6137
+ repo,
6138
+ ref: `heads/${newBranchName}`,
6139
+ sha: createCommitResponse.data.sha
6140
+ });
6141
+ const createPRResponse = await octokit.rest.pulls.create({
6142
+ owner,
6143
+ repo,
6144
+ title,
6145
+ head: newBranchName,
6146
+ head_repo: sourceRepo,
6147
+ body,
6148
+ base: defaultBranch
6149
+ });
6150
+ return {
6151
+ pull_request_url: createPRResponse.data.html_url
6152
+ };
6153
+ },
6154
+ async getGithubBranchList(repoUrl) {
6155
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
6156
+ return octokit.rest.repos.listBranches({
6157
+ owner,
6158
+ repo,
6159
+ per_page: MAX_BRANCHES_FETCH,
6160
+ page: 1
6161
+ });
6162
+ },
6163
+ async createPullRequest(options) {
6164
+ const { owner, repo } = parseGithubOwnerAndRepo(options.repoUrl);
6165
+ return octokit.rest.pulls.create({
6166
+ owner,
6167
+ repo,
6168
+ title: options.title,
6169
+ body: options.body,
6170
+ head: options.sourceBranchName,
6171
+ base: options.targetBranchName,
6172
+ draft: false,
6173
+ maintainer_can_modify: true
6174
+ });
6175
+ },
6176
+ async forkRepo(options) {
6177
+ const { owner, repo } = parseGithubOwnerAndRepo(options.repoUrl);
6178
+ const createForkRes = await octokit.rest.repos.createFork({
6179
+ owner,
6180
+ repo,
6181
+ default_branch_only: false
6182
+ });
6183
+ return { url: createForkRes.data.html_url };
6184
+ },
6185
+ async getUserInfo() {
6186
+ return octokit.request(GET_USER);
6035
6187
  }
6036
- throw e;
6037
- });
6038
- if (response.ok)
6039
- return {
6040
- body: await processBody(response),
6041
- headers: Object.fromEntries(response.headers.entries()),
6042
- status: response.status
6043
- };
6044
- throw new Error(`gitbeaker: ${response.statusText}`);
6188
+ };
6045
6189
  }
6046
6190
 
6047
- // src/features/analysis/scm/gitlab/GitlabSCMLib.ts
6048
- var GitlabSCMLib = class extends SCMLib {
6191
+ // src/features/analysis/scm/github/GithubSCMLib.ts
6192
+ var GithubSCMLib = class extends SCMLib {
6193
+ // we don't always need a url, what's important is that we have an access token
6049
6194
  constructor(url, accessToken, scmOrg) {
6050
6195
  super(url, accessToken, scmOrg);
6196
+ __publicField(this, "githubSdk");
6197
+ this.githubSdk = getGithubSdk({
6198
+ auth: accessToken,
6199
+ url
6200
+ });
6051
6201
  }
6052
6202
  async createSubmitRequest(params) {
6053
6203
  this._validateAccessTokenAndUrl();
6054
6204
  const { targetBranchName, sourceBranchName, title, body } = params;
6055
- return String(
6056
- await createMergeRequest({
6057
- title,
6058
- body,
6059
- targetBranchName,
6060
- sourceBranchName,
6061
- repoUrl: this.url,
6062
- accessToken: this.accessToken
6063
- })
6064
- );
6065
- }
6066
- async validateParams() {
6067
- return gitlabValidateParams({
6068
- url: this.url,
6069
- accessToken: this.accessToken
6070
- });
6071
- }
6072
- async getRepoList(_scmOrg) {
6073
- if (!this.accessToken) {
6074
- console.error("no access token");
6075
- throw new Error("no access token");
6076
- }
6077
- return getGitlabRepoList(this.url, this.accessToken);
6078
- }
6079
- async getBranchList() {
6080
- this._validateAccessTokenAndUrl();
6081
- return getGitlabBranchList({
6082
- accessToken: this.accessToken,
6205
+ const pullRequestResult = await this.githubSdk.createPullRequest({
6206
+ title,
6207
+ body,
6208
+ targetBranchName,
6209
+ sourceBranchName,
6083
6210
  repoUrl: this.url
6084
6211
  });
6212
+ return String(pullRequestResult.data.number);
6085
6213
  }
6086
- get scmLibType() {
6087
- return "GITLAB" /* GITLAB */;
6088
- }
6089
- getAuthHeaders() {
6090
- if (!this.accessToken) {
6091
- return {};
6092
- }
6093
- if (this.accessToken.startsWith("glpat-")) {
6094
- return {
6095
- "Private-Token": this.accessToken
6096
- };
6097
- } else {
6098
- return { authorization: `Bearer ${this.accessToken}` };
6099
- }
6100
- }
6101
- getDownloadUrl(sha) {
6102
- const urlObj = new URL(this.url || "");
6103
- const ProjectId = encodeURIComponent(
6104
- urlObj.pathname.replace(/^\//, "").replace(/\/$/, "")
6105
- );
6106
- return Promise.resolve(
6107
- //We are moving away from this form as it doesn't work when using a non-human token (group/project token)
6108
- //Where as the API zip endpoint works with any token
6109
- //`${this.url}/-/archive/${sha}/${repoName}-${sha}.zip`
6110
- `${urlObj.origin}/api/v4/projects/${ProjectId}/repository/archive.zip?sha=${sha}`
6111
- );
6112
- }
6113
- async _getUsernameForAuthUrl() {
6114
- if (this?.accessToken?.startsWith("glpat-")) {
6115
- return this.getUsername();
6116
- } else {
6117
- return "oauth2";
6118
- }
6119
- }
6120
- async getIsRemoteBranch(branch) {
6121
- this._validateAccessTokenAndUrl();
6122
- return getGitlabIsRemoteBranch({
6123
- accessToken: this.accessToken,
6124
- repoUrl: this.url,
6125
- branch
6126
- });
6127
- }
6128
- async getUserHasAccessToRepo() {
6129
- this._validateAccessTokenAndUrl();
6130
- return getGitlabIsUserCollaborator({
6131
- accessToken: this.accessToken,
6132
- repoUrl: this.url
6214
+ async forkRepo(repoUrl) {
6215
+ this._validateAccessToken();
6216
+ return this.githubSdk.forkRepo({
6217
+ repoUrl
6133
6218
  });
6134
6219
  }
6135
- async getUsername() {
6136
- this._validateAccessTokenAndUrl();
6137
- return getGitlabUsername(this.url, this.accessToken);
6138
- }
6139
- async getSubmitRequestStatus(scmSubmitRequestId) {
6220
+ async createOrUpdateRepositorySecret(params) {
6140
6221
  this._validateAccessTokenAndUrl();
6141
- const state = await getGitlabMergeRequestStatus({
6142
- accessToken: this.accessToken,
6143
- repoUrl: this.url,
6144
- mrNumber: Number(scmSubmitRequestId)
6222
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6223
+ const { data: repositoryPublicKeyResponse } = await this.githubSdk.getRepositoryPublicKey({ owner, repo });
6224
+ const { key_id, key } = repositoryPublicKeyResponse;
6225
+ const encryptedValue = await encryptSecret(params.value, key);
6226
+ return this.githubSdk.createOrUpdateRepositorySecret({
6227
+ encrypted_value: encryptedValue,
6228
+ secret_name: params.name,
6229
+ key_id,
6230
+ owner,
6231
+ repo
6145
6232
  });
6146
- switch (state) {
6147
- case gitlabMergeRequestStatus.merged:
6148
- return "merged";
6149
- case gitlabMergeRequestStatus.opened:
6150
- return "open";
6151
- case gitlabMergeRequestStatus.closed:
6152
- return "closed";
6153
- default:
6154
- throw new Error(`unknown state ${state}`);
6155
- }
6156
6233
  }
6157
- async addCommentToSubmitRequest(submitRequestId, comment) {
6158
- this._validateAccessTokenAndUrl();
6159
- await createMarkdownCommentOnPullRequest({
6160
- accessToken: this.accessToken,
6161
- repoUrl: this.url,
6162
- mrNumber: Number(submitRequestId),
6163
- markdownComment: comment
6234
+ async createPullRequestWithNewFile(sourceRepoUrl, filesPaths, userRepoUrl, title, body) {
6235
+ const { pull_request_url } = await this.githubSdk.createPr({
6236
+ sourceRepoUrl,
6237
+ filesPaths,
6238
+ userRepoUrl,
6239
+ title,
6240
+ body
6164
6241
  });
6242
+ return { pull_request_url };
6165
6243
  }
6166
- async getRepoBlameRanges(ref, path8) {
6167
- this._validateUrl();
6168
- return await getGitlabBlameRanges(
6169
- { ref, path: path8, gitlabUrl: this.url },
6170
- {
6171
- url: this.url,
6172
- gitlabAuthToken: this.accessToken
6173
- }
6174
- );
6175
- }
6176
- async getReferenceData(ref) {
6177
- this._validateUrl();
6178
- return await getGitlabReferenceData(
6179
- { ref, gitlabUrl: this.url },
6180
- {
6181
- url: this.url,
6182
- gitlabAuthToken: this.accessToken
6183
- }
6184
- );
6185
- }
6186
- async getRepoDefaultBranch() {
6187
- this._validateUrl();
6188
- return await getGitlabRepoDefaultBranch(this.url, {
6189
- url: this.url,
6190
- gitlabAuthToken: this.accessToken
6244
+ async validateParams() {
6245
+ return githubValidateParams(this.url, this.accessToken);
6246
+ }
6247
+ async postPrComment(params) {
6248
+ this._validateAccessTokenAndUrl();
6249
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6250
+ return this.githubSdk.postPrComment({
6251
+ ...params,
6252
+ owner,
6253
+ repo
6191
6254
  });
6192
6255
  }
6193
- async getSubmitRequestUrl(submitRequestUrl) {
6256
+ async updatePrComment(params) {
6194
6257
  this._validateAccessTokenAndUrl();
6195
- const res = await getGitlabMergeRequest({
6196
- url: this.url,
6197
- prNumber: submitRequestUrl,
6198
- accessToken: this.accessToken
6258
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6259
+ return this.githubSdk.updatePrComment({
6260
+ ...params,
6261
+ owner,
6262
+ repo
6199
6263
  });
6200
- return res.web_url;
6201
6264
  }
6202
- async getSubmitRequestId(submitRequestUrl) {
6203
- const match = submitRequestUrl.match(/\/merge_requests\/(\d+)/);
6204
- return match?.[1] || "";
6265
+ async deleteComment(params) {
6266
+ this._validateAccessTokenAndUrl();
6267
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6268
+ return this.githubSdk.deleteComment({
6269
+ ...params,
6270
+ owner,
6271
+ repo
6272
+ });
6205
6273
  }
6206
- async getCommitUrl(commitId) {
6274
+ async getPrComments(params) {
6207
6275
  this._validateAccessTokenAndUrl();
6208
- const res = await getGitlabCommitUrl({
6209
- url: this.url,
6210
- commitSha: commitId,
6211
- accessToken: this.accessToken
6276
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6277
+ return this.githubSdk.getPrComments({
6278
+ per_page: 100,
6279
+ ...params,
6280
+ owner,
6281
+ repo
6212
6282
  });
6213
- return res.web_url;
6214
6283
  }
6215
- };
6216
-
6217
- // src/features/analysis/scm/scmFactory.ts
6218
- import { z as z23 } from "zod";
6219
-
6220
- // src/features/analysis/scm/StubSCMLib.ts
6221
- var StubSCMLib = class extends SCMLib {
6222
- constructor(url, accessToken, scmOrg) {
6223
- super(url, accessToken, scmOrg);
6284
+ async getPrDiff(params) {
6285
+ this._validateAccessTokenAndUrl();
6286
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6287
+ const prRes = await this.githubSdk.getPrDiff({
6288
+ ...params,
6289
+ owner,
6290
+ repo
6291
+ });
6292
+ return z22.string().parse(prRes.data);
6224
6293
  }
6225
- async getUrlWithCredentials() {
6226
- console.warn("getUrlWithCredentials() returning empty string");
6227
- return "";
6294
+ async getRepoList(_scmOrg) {
6295
+ this._validateAccessToken();
6296
+ return this.githubSdk.getGithubRepoList();
6228
6297
  }
6229
- async createSubmitRequest(_params) {
6230
- console.warn("createSubmitRequest() returning empty string");
6231
- return "";
6298
+ async getBranchList() {
6299
+ this._validateAccessTokenAndUrl();
6300
+ const branches = await this.githubSdk.getGithubBranchList(this.url);
6301
+ return branches.data.map((branch) => branch.name);
6232
6302
  }
6233
6303
  get scmLibType() {
6234
- console.warn("scmLibType returning GITHUB as default");
6235
6304
  return "GITHUB" /* GITHUB */;
6236
6305
  }
6237
6306
  getAuthHeaders() {
6238
- console.warn("getAuthHeaders() returning empty object");
6307
+ if (this.accessToken) {
6308
+ return { authorization: `Bearer ${this.accessToken}` };
6309
+ }
6239
6310
  return {};
6240
6311
  }
6241
- async getDownloadUrl(_sha) {
6242
- console.warn("getDownloadUrl() returning empty string");
6243
- return "";
6244
- }
6245
- async getIsRemoteBranch(_branch) {
6246
- console.warn("getIsRemoteBranch() returning false");
6247
- return false;
6248
- }
6249
- async validateParams() {
6250
- console.warn("validateParams() no-op");
6251
- }
6252
- async getRepoList(_scmOrg) {
6253
- console.warn("getRepoList() returning empty array");
6254
- return [];
6255
- }
6256
- async getBranchList() {
6257
- console.warn("getBranchList() returning empty array");
6258
- return [];
6312
+ getDownloadUrl(sha) {
6313
+ this._validateUrl();
6314
+ const res = parseScmURL(this.url, "GitHub" /* GitHub */);
6315
+ if (!res) {
6316
+ throw new InvalidRepoUrlError("invalid repo url");
6317
+ }
6318
+ const { protocol, hostname, organization, repoName } = res;
6319
+ const downloadUrl = isGithubOnPrem(this.url) ? `${protocol}//${hostname}/api/v3/repos/${organization}/${repoName}/zipball/${sha}` : `https://api.${hostname}/repos/${organization}/${repoName}/zipball/${sha}`;
6320
+ return Promise.resolve(downloadUrl);
6259
6321
  }
6260
- async getUsername() {
6261
- console.warn("getUsername() returning empty string");
6262
- return "";
6322
+ async _getUsernameForAuthUrl() {
6323
+ return this.getUsername();
6263
6324
  }
6264
- async getSubmitRequestStatus(_scmSubmitRequestId) {
6265
- console.warn("getSubmitRequestStatus() returning ERROR");
6266
- return "error";
6325
+ async getIsRemoteBranch(branch) {
6326
+ this._validateUrl();
6327
+ return this.githubSdk.getGithubIsRemoteBranch({ branch, repoUrl: this.url });
6267
6328
  }
6268
6329
  async getUserHasAccessToRepo() {
6269
- console.warn("getUserHasAccessToRepo() returning false");
6270
- return false;
6271
- }
6272
- async getRepoBlameRanges(_ref, _path) {
6273
- console.warn("getRepoBlameRanges() returning empty array");
6274
- return [];
6275
- }
6276
- async getReferenceData(_ref) {
6277
- console.warn("getReferenceData() returning null/empty defaults");
6278
- return {
6279
- type: "BRANCH" /* BRANCH */,
6280
- sha: "",
6281
- date: void 0
6282
- };
6283
- }
6284
- async getRepoDefaultBranch() {
6285
- console.warn("getRepoDefaultBranch() returning empty string");
6286
- return "";
6287
- }
6288
- async getSubmitRequestUrl(_submitRequestIdNumber) {
6289
- console.warn("getSubmitRequestUrl() returning empty string");
6290
- return "";
6291
- }
6292
- async getSubmitRequestId(_submitRequestUrl) {
6293
- console.warn("getSubmitRequestId() returning empty string");
6294
- return "";
6295
- }
6296
- async getCommitUrl(_commitId) {
6297
- console.warn("getCommitUrl() returning empty string");
6298
- return "";
6299
- }
6300
- async _getUsernameForAuthUrl() {
6301
- console.warn("_getUsernameForAuthUrl() returning empty string");
6302
- return "";
6330
+ this._validateAccessTokenAndUrl();
6331
+ const username = await this.getUsername();
6332
+ return this.githubSdk.getGithubIsUserCollaborator({
6333
+ repoUrl: this.url,
6334
+ username
6335
+ });
6303
6336
  }
6304
- async addCommentToSubmitRequest(_submitRequestId, _comment) {
6305
- console.warn("addCommentToSubmitRequest() no-op");
6337
+ async getUsername() {
6338
+ this._validateAccessToken();
6339
+ return this.githubSdk.getGithubUsername();
6306
6340
  }
6307
- };
6308
-
6309
- // src/features/analysis/scm/scmFactory.ts
6310
- async function createScmLib({ url, accessToken, scmType, scmOrg }, { propagateExceptions = false } = {}) {
6311
- const trimmedUrl = url ? url.trim().replace(/\/$/, "").replace(/.git$/i, "") : void 0;
6312
- try {
6313
- switch (scmType) {
6314
- case "GITHUB" /* GITHUB */: {
6315
- const scm = new GithubSCMLib(trimmedUrl, accessToken, scmOrg);
6316
- await scm.validateParams();
6317
- return scm;
6318
- }
6319
- case "GITLAB" /* GITLAB */: {
6320
- const scm = new GitlabSCMLib(trimmedUrl, accessToken, scmOrg);
6321
- await scm.validateParams();
6322
- return scm;
6323
- }
6324
- case "ADO" /* ADO */: {
6325
- const scm = new AdoSCMLib(trimmedUrl, accessToken, scmOrg);
6326
- await scm.getAdoSdk();
6327
- await scm.validateParams();
6328
- return scm;
6329
- }
6330
- case "BITBUCKET" /* BITBUCKET */: {
6331
- const scm = new BitbucketSCMLib(trimmedUrl, accessToken, scmOrg);
6332
- await scm.validateParams();
6333
- return scm;
6334
- }
6335
- }
6336
- } catch (e) {
6337
- if (e instanceof InvalidRepoUrlError && url) {
6338
- throw new RepoNoTokenAccessError(
6339
- "no access to repo",
6340
- scmLibScmTypeToScmType[z23.nativeEnum(ScmLibScmType).parse(scmType)]
6341
- );
6342
- }
6343
- console.error(`error validating scm: ${scmType} `, e);
6344
- if (propagateExceptions) {
6345
- throw e;
6346
- }
6341
+ async getSubmitRequestStatus(scmSubmitRequestId) {
6342
+ this._validateAccessTokenAndUrl();
6343
+ return this.githubSdk.getGithubPullRequestStatus({
6344
+ repoUrl: this.url,
6345
+ prNumber: Number(scmSubmitRequestId)
6346
+ });
6347
6347
  }
6348
- return new StubSCMLib(trimmedUrl, void 0, void 0);
6349
- }
6350
-
6351
- // src/features/analysis/scm/github/utils/utils.ts
6352
- function parseGithubOwnerAndRepo(gitHubUrl) {
6353
- gitHubUrl = normalizeUrl(gitHubUrl);
6354
- const parsingResult = parseScmURL(gitHubUrl, "GitHub" /* GitHub */);
6355
- if (!parsingResult) {
6356
- throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
6348
+ async addCommentToSubmitRequest(submitRequestId, comment) {
6349
+ this._validateAccessTokenAndUrl();
6350
+ await this.githubSdk.createMarkdownCommentOnPullRequest({
6351
+ repoUrl: this.url,
6352
+ prNumber: Number(submitRequestId),
6353
+ markdownComment: comment
6354
+ });
6357
6355
  }
6358
- const { organization, repoName } = parsingResult;
6359
- if (!organization || !repoName) {
6360
- throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
6356
+ async getRepoBlameRanges(ref, path8) {
6357
+ this._validateUrl();
6358
+ return await this.githubSdk.getGithubBlameRanges({
6359
+ ref,
6360
+ path: path8,
6361
+ gitHubUrl: this.url
6362
+ });
6361
6363
  }
6362
- return { owner: organization, repo: repoName };
6363
- }
6364
- function isGithubOnPrem(url) {
6365
- if (!url) {
6366
- return false;
6364
+ async getReferenceData(ref) {
6365
+ this._validateUrl();
6366
+ return this.githubSdk.getGithubReferenceData({ ref, gitHubUrl: this.url });
6367
6367
  }
6368
- return !url.includes(scmCloudUrl.GitHub);
6369
- }
6370
- function getFetch(url) {
6371
- if (url && isBrokerUrl(url)) {
6372
- const dispatcher = new ProxyAgent2({
6373
- uri: GIT_PROXY_HOST,
6374
- requestTls: {
6375
- rejectUnauthorized: false
6376
- }
6368
+ async getPrComment(commentId) {
6369
+ this._validateUrl();
6370
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6371
+ return await this.githubSdk.getPrComment({
6372
+ repo,
6373
+ owner,
6374
+ comment_id: commentId
6377
6375
  });
6378
- return (input, init) => {
6379
- return fetch2(input, {
6380
- ...init,
6381
- dispatcher
6382
- });
6383
- };
6384
6376
  }
6385
- return fetch2;
6386
- }
6387
- function getRandomGithubCloudAnonToken() {
6388
- if (!GITHUB_API_TOKEN || typeof GITHUB_API_TOKEN !== "string") {
6389
- return void 0;
6377
+ async getRepoDefaultBranch() {
6378
+ this._validateUrl();
6379
+ return await this.githubSdk.getGithubRepoDefaultBranch(this.url);
6390
6380
  }
6391
- const tokens = GITHUB_API_TOKEN.split(",");
6392
- return tokens[Math.floor(Math.random() * tokens.length)];
6393
- }
6394
- function getOctoKit(options) {
6395
- const token = !options?.auth && !isGithubOnPrem(options?.url) ? getRandomGithubCloudAnonToken() : options?.auth;
6396
- const baseUrl = options?.url && isGithubOnPrem(options.url) ? `${new URL(options.url).origin}/api/v3` : void 0;
6397
- return new Octokit({
6398
- ...options,
6399
- auth: token,
6400
- baseUrl,
6401
- //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
6402
- //to debug the performance of these API calls.
6403
- log: GITHUB_API_TOKEN ? console : void 0,
6404
- request: {
6405
- fetch: getFetch(baseUrl)
6406
- },
6407
- retry: {
6408
- enabled: false
6409
- },
6410
- throttle: {
6411
- enabled: false
6412
- }
6413
- });
6414
- }
6415
- function isGithubActionActionToken(token) {
6416
- return token.startsWith("ghs_");
6417
- }
6418
- async function githubValidateParams(url, accessToken) {
6419
- try {
6420
- const oktoKit = getOctoKit({ auth: accessToken, url });
6421
- if (accessToken && !isGithubActionActionToken(accessToken)) {
6422
- await oktoKit.rest.users.getAuthenticated();
6423
- }
6424
- if (url && shouldValidateUrl(url)) {
6425
- const { owner, repo } = parseGithubOwnerAndRepo(url);
6426
- await oktoKit.request(GET_REPO_BRANCHES, {
6427
- owner,
6428
- repo,
6429
- per_page: 1
6430
- });
6431
- }
6432
- } catch (e) {
6433
- console.log("could not init github scm", e);
6434
- const error = e;
6435
- const code = error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
6436
- if (code === 401 || code === 403) {
6437
- throw new InvalidAccessTokenError(`invalid github access token`);
6438
- }
6439
- if (code === 404) {
6440
- throw new InvalidRepoUrlError(`invalid github repo Url ${url}`);
6441
- }
6442
- console.log("githubValidateParams error", e);
6443
- throw new InvalidRepoUrlError(
6444
- `cannot access GH repo URL: ${url} with the provided access token`
6445
- );
6381
+ async getSubmitRequestUrl(submitRequestUrl) {
6382
+ this._validateAccessTokenAndUrl();
6383
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6384
+ const getPrRes = await this.githubSdk.getPr({
6385
+ owner,
6386
+ repo,
6387
+ pull_number: submitRequestUrl
6388
+ });
6389
+ return getPrRes.data.html_url;
6446
6390
  }
6447
- }
6448
-
6449
- // src/features/analysis/scm/github/github.ts
6450
- function getGithubSdk(params = {}) {
6451
- const octokit = getOctoKit(params);
6452
- return {
6453
- async postPrComment(params2) {
6454
- return octokit.request(POST_COMMENT_PATH, params2);
6455
- },
6456
- async updatePrComment(params2) {
6457
- return octokit.request(UPDATE_COMMENT_PATH, params2);
6458
- },
6459
- async getPrComments(params2) {
6460
- return octokit.request(GET_PR_COMMENTS_PATH, params2);
6461
- },
6462
- async getPrComment(params2) {
6463
- return octokit.request(GET_PR_COMMENT_PATH, params2);
6464
- },
6465
- async deleteComment(params2) {
6466
- return octokit.request(DELETE_COMMENT_PATH, params2);
6467
- },
6468
- async replyToCodeReviewComment(params2) {
6469
- return octokit.request(REPLY_TO_CODE_REVIEW_COMMENT_PATH, params2);
6470
- },
6471
- async getPrDiff(params2) {
6472
- return octokit.request(GET_PR, {
6473
- ...params2,
6474
- mediaType: { format: "diff" }
6475
- });
6476
- },
6477
- async getPr(params2) {
6478
- return octokit.request(GET_PR, { ...params2 });
6479
- },
6480
- async createOrUpdateRepositorySecret(params2) {
6481
- return octokit.request(CREATE_OR_UPDATE_A_REPOSITORY_SECRET, params2);
6482
- },
6483
- async getRepositoryPublicKey(params2) {
6484
- return octokit.request(GET_A_REPOSITORY_PUBLIC_KEY, params2);
6485
- },
6486
- async postGeneralPrComment(params2) {
6487
- return octokit.request(POST_GENERAL_PR_COMMENT, params2);
6488
- },
6489
- async getGeneralPrComments(params2) {
6490
- return octokit.request(GET_GENERAL_PR_COMMENTS, params2);
6491
- },
6492
- async deleteGeneralPrComment(params2) {
6493
- return octokit.request(DELETE_GENERAL_PR_COMMENT, params2);
6494
- },
6495
- async getGithubUsername() {
6496
- const res = await octokit.rest.users.getAuthenticated();
6497
- return res.data.login;
6498
- },
6499
- async getGithubIsUserCollaborator(params2) {
6500
- const { username, repoUrl } = params2;
6501
- try {
6502
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
6503
- const res = await octokit.rest.repos.checkCollaborator({
6504
- owner,
6505
- repo,
6506
- username
6507
- });
6508
- if (res.status === 204) {
6509
- return true;
6510
- }
6511
- } catch (e) {
6512
- return false;
6513
- }
6514
- return false;
6515
- },
6516
- async getGithubPullRequestStatus(params2) {
6517
- const { repoUrl, prNumber } = params2;
6518
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
6519
- const res = await octokit.rest.pulls.get({
6520
- owner,
6521
- repo,
6522
- pull_number: prNumber
6523
- });
6524
- if (res.data.merged) {
6525
- return "merged";
6526
- }
6527
- if (res.data.draft) {
6528
- return "draft";
6529
- }
6530
- return res.data.state;
6531
- },
6532
- async createMarkdownCommentOnPullRequest(params2) {
6533
- const { repoUrl, prNumber, markdownComment } = params2;
6534
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
6535
- return octokit.rest.issues.createComment({
6536
- owner,
6537
- repo,
6538
- issue_number: prNumber,
6539
- body: markdownComment
6540
- });
6541
- },
6542
- async getGithubIsRemoteBranch(params2) {
6543
- const { repoUrl, branch } = params2;
6544
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
6545
- try {
6546
- const res = await octokit.rest.repos.getBranch({
6547
- owner,
6548
- repo,
6549
- branch
6550
- });
6551
- return branch === res.data.name;
6552
- } catch (e) {
6553
- return false;
6554
- }
6555
- },
6556
- async getGithubRepoList() {
6557
- try {
6558
- const githubRepos = await octokit.request(GET_USER_REPOS, {
6559
- sort: "updated"
6560
- });
6561
- return githubRepos.data.map((repo) => ({
6562
- repoName: repo.name,
6563
- repoUrl: repo.html_url,
6564
- repoOwner: repo.owner.login,
6565
- repoLanguages: repo.language ? [repo.language] : [],
6566
- repoIsPublic: !repo.private,
6567
- repoUpdatedAt: repo.updated_at
6568
- }));
6569
- } catch (e) {
6570
- if (e instanceof RequestError && e.status === 401) {
6571
- return [];
6572
- }
6573
- if (e instanceof RequestError && e.status === 404) {
6574
- return [];
6575
- }
6576
- throw e;
6577
- }
6578
- },
6579
- async getGithubRepoDefaultBranch(repoUrl) {
6580
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
6581
- const repos = await octokit.rest.repos.get({ repo, owner });
6582
- return repos.data.default_branch;
6583
- },
6584
- async getGithubReferenceData({
6585
- ref,
6586
- gitHubUrl
6587
- }) {
6588
- const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
6589
- let res;
6590
- try {
6591
- res = await Promise.any([
6592
- this.getBranch({ owner, repo, branch: ref }).then((result) => ({
6593
- date: result.data.commit.commit.committer?.date ? new Date(result.data.commit.commit.committer?.date) : void 0,
6594
- type: "BRANCH" /* BRANCH */,
6595
- sha: result.data.commit.sha
6596
- })),
6597
- this.getCommit({ commitSha: ref, repo, owner }).then((commit) => ({
6598
- date: new Date(commit.data.committer.date),
6599
- type: "COMMIT" /* COMMIT */,
6600
- sha: commit.data.sha
6601
- })),
6602
- this.getTagDate({ owner, repo, tag: ref }).then((data) => ({
6603
- date: new Date(data.date),
6604
- type: "TAG" /* TAG */,
6605
- sha: data.sha
6606
- }))
6607
- ]);
6608
- return res;
6609
- } catch (e) {
6610
- if (e instanceof AggregateError) {
6611
- throw new RefNotFoundError(`ref: ${ref} does not exist`);
6612
- }
6613
- throw e;
6614
- }
6615
- },
6616
- async getBranch({
6617
- branch,
6391
+ async getSubmitRequestId(submitRequestUrl) {
6392
+ const match = submitRequestUrl.match(/\/pull\/(\d+)/);
6393
+ return match?.[1] || "";
6394
+ }
6395
+ async getCommitUrl(commitId) {
6396
+ this._validateAccessTokenAndUrl();
6397
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6398
+ const getCommitRes = await this.githubSdk.getCommit({
6618
6399
  owner,
6619
- repo
6620
- }) {
6621
- return octokit.rest.repos.getBranch({
6622
- branch,
6623
- owner,
6624
- repo
6625
- });
6626
- },
6627
- async getCommit({
6628
- commitSha,
6400
+ repo,
6401
+ commitSha: commitId
6402
+ });
6403
+ return getCommitRes.data.html_url;
6404
+ }
6405
+ async postGeneralPrComment(params) {
6406
+ const { prNumber, body } = params;
6407
+ this._validateAccessTokenAndUrl();
6408
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6409
+ return await this.githubSdk.postGeneralPrComment({
6410
+ issue_number: prNumber,
6629
6411
  owner,
6630
- repo
6631
- }) {
6632
- return octokit.rest.git.getCommit({
6633
- repo,
6634
- owner,
6635
- commit_sha: commitSha
6636
- });
6637
- },
6638
- async getTagDate({
6639
- tag,
6412
+ repo,
6413
+ body
6414
+ });
6415
+ }
6416
+ async getGeneralPrComments(params) {
6417
+ const { prNumber } = params;
6418
+ this._validateAccessTokenAndUrl();
6419
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6420
+ return await this.githubSdk.getGeneralPrComments({
6421
+ issue_number: prNumber,
6640
6422
  owner,
6641
6423
  repo
6642
- }) {
6643
- const refResponse = await octokit.rest.git.getRef({
6644
- ref: `tags/${tag}`,
6645
- owner,
6646
- repo
6647
- });
6648
- const tagSha = refResponse.data.object.sha;
6649
- if (refResponse.data.object.type === "commit") {
6650
- const res2 = await octokit.rest.git.getCommit({
6651
- commit_sha: tagSha,
6652
- owner,
6653
- repo
6654
- });
6655
- return {
6656
- date: res2.data.committer.date,
6657
- sha: res2.data.sha
6658
- };
6424
+ });
6425
+ }
6426
+ async deleteGeneralPrComment({
6427
+ commentId
6428
+ }) {
6429
+ this._validateAccessTokenAndUrl();
6430
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6431
+ return this.githubSdk.deleteGeneralPrComment({
6432
+ owner,
6433
+ repo,
6434
+ comment_id: commentId
6435
+ });
6436
+ }
6437
+ };
6438
+
6439
+ // src/features/analysis/scm/gitlab/gitlab.ts
6440
+ import querystring3 from "node:querystring";
6441
+ import {
6442
+ createRequesterFn
6443
+ } from "@gitbeaker/requester-utils";
6444
+ import {
6445
+ AccessLevel,
6446
+ Gitlab
6447
+ } from "@gitbeaker/rest";
6448
+ import Debug4 from "debug";
6449
+ import {
6450
+ fetch as undiciFetch,
6451
+ ProxyAgent as ProxyAgent2
6452
+ } from "undici";
6453
+
6454
+ // src/features/analysis/scm/gitlab/types.ts
6455
+ import { z as z23 } from "zod";
6456
+ var GitlabAuthResultZ = z23.object({
6457
+ access_token: z23.string(),
6458
+ token_type: z23.string(),
6459
+ refresh_token: z23.string()
6460
+ });
6461
+
6462
+ // src/features/analysis/scm/gitlab/gitlab.ts
6463
+ var debug4 = Debug4("scm:gitlab");
6464
+ function removeTrailingSlash2(str) {
6465
+ return str.trim().replace(/\/+$/, "");
6466
+ }
6467
+ function getRandomGitlabCloudAnonToken() {
6468
+ if (!GITLAB_API_TOKEN || typeof GITLAB_API_TOKEN !== "string") {
6469
+ return void 0;
6470
+ }
6471
+ const tokens = GITLAB_API_TOKEN.split(",");
6472
+ return tokens[Math.floor(Math.random() * tokens.length)];
6473
+ }
6474
+ function getGitBeaker(options) {
6475
+ const token = options?.gitlabAuthToken ?? getRandomGitlabCloudAnonToken() ?? "";
6476
+ const url = options.url;
6477
+ const host = url ? new URL(url).origin : "https://gitlab.com";
6478
+ if (token?.startsWith("glpat-") || token === "") {
6479
+ return new Gitlab({
6480
+ token,
6481
+ host,
6482
+ requesterFn: createRequesterFn(
6483
+ (_, reqo) => Promise.resolve(reqo),
6484
+ brokerRequestHandler
6485
+ )
6486
+ });
6487
+ }
6488
+ return new Gitlab({
6489
+ oauthToken: token,
6490
+ host,
6491
+ requesterFn: createRequesterFn(
6492
+ (_, reqo) => Promise.resolve(reqo),
6493
+ brokerRequestHandler
6494
+ )
6495
+ });
6496
+ }
6497
+ async function gitlabValidateParams({
6498
+ url,
6499
+ accessToken
6500
+ }) {
6501
+ try {
6502
+ const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
6503
+ if (accessToken) {
6504
+ await api2.Users.showCurrentUser();
6505
+ }
6506
+ if (url && shouldValidateUrl(url)) {
6507
+ const { projectPath } = parseGitlabOwnerAndRepo(url);
6508
+ await api2.Projects.show(projectPath);
6509
+ }
6510
+ } catch (e) {
6511
+ const error = e;
6512
+ const code = error.code || error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
6513
+ const description = error.description || `${e}`;
6514
+ if (code === 401 || code === 403 || description.includes("401") || description.includes("403")) {
6515
+ throw new InvalidAccessTokenError(`invalid gitlab access token`);
6516
+ }
6517
+ if (code === 404 || description.includes("404") || description.includes("Not Found")) {
6518
+ throw new InvalidRepoUrlError(`invalid gitlab repo URL: ${url}`);
6519
+ }
6520
+ console.log("gitlabValidateParams error", e);
6521
+ throw new InvalidRepoUrlError(
6522
+ `cannot access gitlab repo URL: ${url} with the provided access token`
6523
+ );
6524
+ }
6525
+ }
6526
+ async function getGitlabUsername(url, accessToken) {
6527
+ const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
6528
+ const res = await api2.Users.showCurrentUser();
6529
+ return res.username;
6530
+ }
6531
+ async function getGitlabIsUserCollaborator({
6532
+ accessToken,
6533
+ repoUrl
6534
+ }) {
6535
+ try {
6536
+ const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
6537
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
6538
+ const proj = await api2.Projects.show(projectPath);
6539
+ const groupAccess = proj.permissions?.group_access?.access_level || 0;
6540
+ const projectAccess = proj.permissions?.project_access?.access_level || 0;
6541
+ const accessLevelWithWriteAccess = [
6542
+ AccessLevel.DEVELOPER,
6543
+ AccessLevel.MAINTAINER,
6544
+ AccessLevel.OWNER,
6545
+ AccessLevel.ADMIN
6546
+ ];
6547
+ return accessLevelWithWriteAccess.includes(groupAccess) || accessLevelWithWriteAccess.includes(projectAccess);
6548
+ } catch (e) {
6549
+ return false;
6550
+ }
6551
+ }
6552
+ var gitlabMergeRequestStatus = {
6553
+ merged: "merged",
6554
+ opened: "opened",
6555
+ closed: "closed"
6556
+ };
6557
+ async function getGitlabMergeRequestStatus({
6558
+ accessToken,
6559
+ repoUrl,
6560
+ mrNumber
6561
+ }) {
6562
+ const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
6563
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
6564
+ const res = await api2.MergeRequests.show(projectPath, mrNumber);
6565
+ switch (res.state) {
6566
+ case gitlabMergeRequestStatus.merged:
6567
+ case gitlabMergeRequestStatus.opened:
6568
+ case gitlabMergeRequestStatus.closed:
6569
+ return res.state;
6570
+ default:
6571
+ throw new Error(`unknown merge request state ${res.state}`);
6572
+ }
6573
+ }
6574
+ async function createMarkdownCommentOnPullRequest({
6575
+ markdownComment,
6576
+ accessToken,
6577
+ repoUrl,
6578
+ mrNumber
6579
+ }) {
6580
+ const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
6581
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
6582
+ return api2.MergeRequestNotes.create(projectPath, mrNumber, markdownComment);
6583
+ }
6584
+ async function getGitlabIsRemoteBranch({
6585
+ accessToken,
6586
+ repoUrl,
6587
+ branch
6588
+ }) {
6589
+ const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
6590
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
6591
+ try {
6592
+ const res = await api2.Branches.show(projectPath, branch);
6593
+ return res.name === branch;
6594
+ } catch (e) {
6595
+ return false;
6596
+ }
6597
+ }
6598
+ async function getGitlabRepoList(url, accessToken) {
6599
+ const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
6600
+ const res = await api2.Projects.all({
6601
+ membership: true,
6602
+ //TODO: a bug in the sorting mechanism of this api call
6603
+ //disallows us to sort by updated_at in descending order
6604
+ //so we have to sort by updated_at in ascending order.
6605
+ //We can wait for the bug to be fixed or call the api
6606
+ //directly with fetch()
6607
+ sort: "asc",
6608
+ orderBy: "updated_at",
6609
+ perPage: 100
6610
+ });
6611
+ return Promise.all(
6612
+ res.map(async (project) => {
6613
+ const proj = await api2.Projects.show(project.id);
6614
+ const owner = proj.namespace.name;
6615
+ const repoLanguages = await api2.Projects.showLanguages(project.id);
6616
+ return {
6617
+ repoName: project.path,
6618
+ repoUrl: project.web_url,
6619
+ repoOwner: owner,
6620
+ repoLanguages: Object.keys(repoLanguages),
6621
+ repoIsPublic: project.visibility === "public",
6622
+ repoUpdatedAt: project.last_activity_at
6623
+ };
6624
+ })
6625
+ );
6626
+ }
6627
+ async function getGitlabBranchList({
6628
+ accessToken,
6629
+ repoUrl
6630
+ }) {
6631
+ const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
6632
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
6633
+ try {
6634
+ const res = await api2.Branches.all(projectPath, {
6635
+ //keyset API pagination is not supported by GL for the branch list (at least not the on-prem version)
6636
+ //so for now we stick with the default pagination and just return the first page and limit the results to 1000 entries.
6637
+ //This is a temporary solution until we implement list branches with name search.
6638
+ perPage: MAX_BRANCHES_FETCH,
6639
+ page: 1
6640
+ });
6641
+ res.sort((a, b) => {
6642
+ if (!a.commit?.committed_date || !b.commit?.committed_date) {
6643
+ return 0;
6659
6644
  }
6660
- const res = await octokit.rest.git.getTag({
6661
- tag_sha: tagSha,
6662
- owner,
6663
- repo
6664
- });
6645
+ return new Date(b.commit?.committed_date).getTime() - new Date(a.commit?.committed_date).getTime();
6646
+ });
6647
+ return res.map((branch) => branch.name).slice(0, MAX_BRANCHES_FETCH);
6648
+ } catch (e) {
6649
+ return [];
6650
+ }
6651
+ }
6652
+ async function createMergeRequest(options) {
6653
+ const { projectPath } = parseGitlabOwnerAndRepo(options.repoUrl);
6654
+ const api2 = getGitBeaker({
6655
+ url: options.repoUrl,
6656
+ gitlabAuthToken: options.accessToken
6657
+ });
6658
+ const res = await api2.MergeRequests.create(
6659
+ projectPath,
6660
+ options.sourceBranchName,
6661
+ options.targetBranchName,
6662
+ options.title,
6663
+ {
6664
+ description: options.body
6665
+ }
6666
+ );
6667
+ return res.iid;
6668
+ }
6669
+ async function getGitlabMergeRequest({
6670
+ url,
6671
+ prNumber,
6672
+ accessToken
6673
+ }) {
6674
+ const { projectPath } = parseGitlabOwnerAndRepo(url);
6675
+ const api2 = getGitBeaker({
6676
+ url,
6677
+ gitlabAuthToken: accessToken
6678
+ });
6679
+ return await api2.MergeRequests.show(projectPath, prNumber);
6680
+ }
6681
+ async function getGitlabCommitUrl({
6682
+ url,
6683
+ commitSha,
6684
+ accessToken
6685
+ }) {
6686
+ const { projectPath } = parseGitlabOwnerAndRepo(url);
6687
+ const api2 = getGitBeaker({
6688
+ url,
6689
+ gitlabAuthToken: accessToken
6690
+ });
6691
+ return await api2.Commits.show(projectPath, commitSha);
6692
+ }
6693
+ async function getGitlabRepoDefaultBranch(repoUrl, options) {
6694
+ const api2 = getGitBeaker({
6695
+ url: repoUrl,
6696
+ gitlabAuthToken: options?.gitlabAuthToken
6697
+ });
6698
+ const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
6699
+ const project = await api2.Projects.show(projectPath);
6700
+ if (!project.default_branch) {
6701
+ throw new Error("no default branch");
6702
+ }
6703
+ return project.default_branch;
6704
+ }
6705
+ async function getGitlabReferenceData({ ref, gitlabUrl }, options) {
6706
+ const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
6707
+ const api2 = getGitBeaker({
6708
+ url: gitlabUrl,
6709
+ gitlabAuthToken: options?.gitlabAuthToken
6710
+ });
6711
+ const results = await Promise.allSettled([
6712
+ (async () => {
6713
+ const res = await api2.Branches.show(projectPath, ref);
6665
6714
  return {
6666
- date: res.data.tagger.date,
6667
- sha: res.data.sha
6715
+ sha: res.commit.id,
6716
+ type: "BRANCH" /* BRANCH */,
6717
+ date: res.commit.committed_date ? new Date(res.commit.committed_date) : void 0
6668
6718
  };
6669
- },
6670
- async getGithubBlameRanges(params2) {
6671
- const { ref, gitHubUrl, path: path8 } = params2;
6672
- const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
6673
- const res = await octokit.graphql(
6674
- GET_BLAME_DOCUMENT,
6675
- {
6676
- owner,
6677
- repo,
6678
- path: path8,
6679
- ref
6680
- }
6681
- );
6682
- if (!res?.repository?.object?.blame?.ranges) {
6683
- return [];
6684
- }
6685
- return res.repository.object.blame.ranges.map((range) => ({
6686
- startingLine: range.startingLine,
6687
- endingLine: range.endingLine,
6688
- email: range.commit.author.user?.email || "",
6689
- name: range.commit.author.user?.name || "",
6690
- login: range.commit.author.user?.login || ""
6691
- }));
6692
- },
6693
- // todo: refactor the name for this function
6694
- async createPr(params2) {
6695
- const { sourceRepoUrl, filesPaths, userRepoUrl, title, body } = params2;
6696
- const { owner: sourceOwner, repo: sourceRepo } = parseGithubOwnerAndRepo(sourceRepoUrl);
6697
- const { owner, repo } = parseGithubOwnerAndRepo(userRepoUrl);
6698
- const [sourceFilePath, secondFilePath] = filesPaths;
6699
- const sourceFileContentResponse = await octokit.rest.repos.getContent({
6700
- owner: sourceOwner,
6701
- repo: sourceRepo,
6702
- path: "/" + sourceFilePath
6703
- });
6704
- const { data: repository } = await octokit.rest.repos.get({ owner, repo });
6705
- const defaultBranch = repository.default_branch;
6706
- const newBranchName = `mobb/workflow-${Date.now()}`;
6707
- await octokit.rest.git.createRef({
6708
- owner,
6709
- repo,
6710
- ref: `refs/heads/${newBranchName}`,
6711
- sha: await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha)
6712
- });
6713
- const decodedContent = Buffer.from(
6714
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6715
- // @ts-ignore
6716
- sourceFileContentResponse.data.content,
6717
- "base64"
6718
- ).toString("utf-8");
6719
- const tree = [
6720
- {
6721
- path: sourceFilePath,
6722
- mode: "100644",
6723
- type: "blob",
6724
- content: decodedContent
6725
- }
6726
- ];
6727
- if (secondFilePath) {
6728
- const secondFileContentResponse = await octokit.rest.repos.getContent({
6729
- owner: sourceOwner,
6730
- repo: sourceRepo,
6731
- path: "/" + secondFilePath
6732
- });
6733
- const secondDecodedContent = Buffer.from(
6734
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6735
- // @ts-ignore
6736
- secondFileContentResponse.data.content,
6737
- "base64"
6738
- ).toString("utf-8");
6739
- tree.push({
6740
- path: secondFilePath,
6741
- mode: "100644",
6742
- type: "blob",
6743
- content: secondDecodedContent
6744
- });
6745
- }
6746
- const createTreeResponse = await octokit.rest.git.createTree({
6747
- owner,
6748
- repo,
6749
- base_tree: await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha),
6750
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6751
- // @ts-ignore
6752
- tree
6753
- });
6754
- const createCommitResponse = await octokit.rest.git.createCommit({
6755
- owner,
6756
- repo,
6757
- message: "Add new yaml file",
6758
- tree: createTreeResponse.data.sha,
6759
- parents: [
6760
- await octokit.rest.git.getRef({ owner, repo, ref: `heads/${defaultBranch}` }).then((response) => response.data.object.sha)
6761
- ]
6762
- });
6763
- await octokit.rest.git.updateRef({
6764
- owner,
6765
- repo,
6766
- ref: `heads/${newBranchName}`,
6767
- sha: createCommitResponse.data.sha
6768
- });
6769
- const createPRResponse = await octokit.rest.pulls.create({
6770
- owner,
6771
- repo,
6772
- title,
6773
- head: newBranchName,
6774
- head_repo: sourceRepo,
6775
- body,
6776
- base: defaultBranch
6777
- });
6719
+ })(),
6720
+ (async () => {
6721
+ const res = await api2.Commits.show(projectPath, ref);
6778
6722
  return {
6779
- pull_request_url: createPRResponse.data.html_url
6723
+ sha: res.id,
6724
+ type: "COMMIT" /* COMMIT */,
6725
+ date: res.committed_date ? new Date(res.committed_date) : void 0
6780
6726
  };
6781
- },
6782
- async getGithubBranchList(repoUrl) {
6783
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
6784
- return octokit.rest.repos.listBranches({
6785
- owner,
6786
- repo,
6787
- per_page: MAX_BRANCHES_FETCH,
6788
- page: 1
6789
- });
6790
- },
6791
- async createPullRequest(options) {
6792
- const { owner, repo } = parseGithubOwnerAndRepo(options.repoUrl);
6793
- return octokit.rest.pulls.create({
6794
- owner,
6795
- repo,
6796
- title: options.title,
6797
- body: options.body,
6798
- head: options.sourceBranchName,
6799
- base: options.targetBranchName,
6800
- draft: false,
6801
- maintainer_can_modify: true
6802
- });
6803
- },
6804
- async forkRepo(options) {
6805
- const { owner, repo } = parseGithubOwnerAndRepo(options.repoUrl);
6806
- const createForkRes = await octokit.rest.repos.createFork({
6807
- owner,
6808
- repo,
6809
- default_branch_only: false
6810
- });
6811
- return { url: createForkRes.data.html_url };
6812
- },
6813
- async getUserInfo() {
6814
- return octokit.request(GET_USER);
6727
+ })(),
6728
+ (async () => {
6729
+ const res = await api2.Tags.show(projectPath, ref);
6730
+ return {
6731
+ sha: res.commit.id,
6732
+ type: "TAG" /* TAG */,
6733
+ date: res.commit.committed_date ? new Date(res.commit.committed_date) : void 0
6734
+ };
6735
+ })()
6736
+ ]);
6737
+ const [branchRes, commitRes, tagRes] = results;
6738
+ if (tagRes.status === "fulfilled") {
6739
+ return tagRes.value;
6740
+ }
6741
+ if (branchRes.status === "fulfilled") {
6742
+ return branchRes.value;
6743
+ }
6744
+ if (commitRes.status === "fulfilled") {
6745
+ return commitRes.value;
6746
+ }
6747
+ throw new RefNotFoundError(`ref: ${ref} does not exist`);
6748
+ }
6749
+ function parseGitlabOwnerAndRepo(gitlabUrl) {
6750
+ gitlabUrl = removeTrailingSlash2(gitlabUrl);
6751
+ const parsingResult = parseScmURL(gitlabUrl, "GitLab" /* GitLab */);
6752
+ if (!parsingResult || !parsingResult.repoName) {
6753
+ throw new InvalidUrlPatternError(`invalid gitlab repo Url ${gitlabUrl}`);
6754
+ }
6755
+ const { organization, repoName, projectPath } = parsingResult;
6756
+ return { owner: organization, repo: repoName, projectPath };
6757
+ }
6758
+ async function getGitlabBlameRanges({ ref, gitlabUrl, path: path8 }, options) {
6759
+ const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
6760
+ const api2 = getGitBeaker({
6761
+ url: gitlabUrl,
6762
+ gitlabAuthToken: options?.gitlabAuthToken
6763
+ });
6764
+ const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path8, ref);
6765
+ let lineNumber = 1;
6766
+ return resp.filter((range) => range.lines).map((range) => {
6767
+ const oldLineNumber = lineNumber;
6768
+ if (!range.lines) {
6769
+ throw new Error("range.lines should not be undefined");
6815
6770
  }
6816
- };
6771
+ lineNumber += range.lines.length;
6772
+ return {
6773
+ startingLine: oldLineNumber,
6774
+ endingLine: lineNumber - 1,
6775
+ login: range.commit.author_email,
6776
+ email: range.commit.author_email,
6777
+ name: range.commit.author_name
6778
+ };
6779
+ });
6780
+ }
6781
+ async function processBody(response) {
6782
+ const headers = response.headers;
6783
+ const type2 = headers.get("content-type")?.split(";")[0]?.trim();
6784
+ if (type2 === "application/json") {
6785
+ return await response.json();
6786
+ }
6787
+ return await response.text();
6788
+ }
6789
+ async function brokerRequestHandler(endpoint, options) {
6790
+ const { prefixUrl, searchParams } = options || {};
6791
+ let baseUrl;
6792
+ if (prefixUrl) baseUrl = prefixUrl.endsWith("/") ? prefixUrl : `${prefixUrl}/`;
6793
+ const url = new URL(endpoint, baseUrl);
6794
+ url.search = searchParams || "";
6795
+ const dispatcher = url && isBrokerUrl(url.href) ? new ProxyAgent2({
6796
+ uri: GIT_PROXY_HOST,
6797
+ requestTls: {
6798
+ rejectUnauthorized: false
6799
+ }
6800
+ }) : void 0;
6801
+ const response = await undiciFetch(url, {
6802
+ headers: options?.headers,
6803
+ method: options?.method,
6804
+ body: options?.body ? String(options?.body) : void 0,
6805
+ dispatcher
6806
+ }).catch((e) => {
6807
+ if (e.name === "TimeoutError" || e.name === "AbortError") {
6808
+ throw new Error("Query timeout was reached");
6809
+ }
6810
+ throw e;
6811
+ });
6812
+ if (response.ok)
6813
+ return {
6814
+ body: await processBody(response),
6815
+ headers: Object.fromEntries(response.headers.entries()),
6816
+ status: response.status
6817
+ };
6818
+ throw new Error(`gitbeaker: ${response.statusText}`);
6817
6819
  }
6818
6820
 
6819
- // src/features/analysis/scm/github/GithubSCMLib.ts
6820
- var GithubSCMLib = class extends SCMLib {
6821
- // we don't always need a url, what's important is that we have an access token
6821
+ // src/features/analysis/scm/gitlab/GitlabSCMLib.ts
6822
+ var GitlabSCMLib = class extends SCMLib {
6822
6823
  constructor(url, accessToken, scmOrg) {
6823
6824
  super(url, accessToken, scmOrg);
6824
- __publicField(this, "githubSdk");
6825
- this.githubSdk = getGithubSdk({
6826
- auth: accessToken,
6827
- url
6828
- });
6829
6825
  }
6830
6826
  async createSubmitRequest(params) {
6831
6827
  this._validateAccessTokenAndUrl();
6832
6828
  const { targetBranchName, sourceBranchName, title, body } = params;
6833
- const pullRequestResult = await this.githubSdk.createPullRequest({
6834
- title,
6835
- body,
6836
- targetBranchName,
6837
- sourceBranchName,
6838
- repoUrl: this.url
6839
- });
6840
- return String(pullRequestResult.data.number);
6841
- }
6842
- async forkRepo(repoUrl) {
6843
- this._validateAccessToken();
6844
- return this.githubSdk.forkRepo({
6845
- repoUrl
6846
- });
6847
- }
6848
- async createOrUpdateRepositorySecret(params) {
6849
- this._validateAccessTokenAndUrl();
6850
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6851
- const { data: repositoryPublicKeyResponse } = await this.githubSdk.getRepositoryPublicKey({ owner, repo });
6852
- const { key_id, key } = repositoryPublicKeyResponse;
6853
- const encryptedValue = await encryptSecret(params.value, key);
6854
- return this.githubSdk.createOrUpdateRepositorySecret({
6855
- encrypted_value: encryptedValue,
6856
- secret_name: params.name,
6857
- key_id,
6858
- owner,
6859
- repo
6860
- });
6861
- }
6862
- async createPullRequestWithNewFile(sourceRepoUrl, filesPaths, userRepoUrl, title, body) {
6863
- const { pull_request_url } = await this.githubSdk.createPr({
6864
- sourceRepoUrl,
6865
- filesPaths,
6866
- userRepoUrl,
6867
- title,
6868
- body
6869
- });
6870
- return { pull_request_url };
6829
+ return String(
6830
+ await createMergeRequest({
6831
+ title,
6832
+ body,
6833
+ targetBranchName,
6834
+ sourceBranchName,
6835
+ repoUrl: this.url,
6836
+ accessToken: this.accessToken
6837
+ })
6838
+ );
6871
6839
  }
6872
6840
  async validateParams() {
6873
- return githubValidateParams(this.url, this.accessToken);
6874
- }
6875
- async postPrComment(params) {
6876
- this._validateAccessTokenAndUrl();
6877
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6878
- return this.githubSdk.postPrComment({
6879
- ...params,
6880
- owner,
6881
- repo
6882
- });
6883
- }
6884
- async updatePrComment(params) {
6885
- this._validateAccessTokenAndUrl();
6886
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6887
- return this.githubSdk.updatePrComment({
6888
- ...params,
6889
- owner,
6890
- repo
6891
- });
6892
- }
6893
- async deleteComment(params) {
6894
- this._validateAccessTokenAndUrl();
6895
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6896
- return this.githubSdk.deleteComment({
6897
- ...params,
6898
- owner,
6899
- repo
6900
- });
6901
- }
6902
- async getPrComments(params) {
6903
- this._validateAccessTokenAndUrl();
6904
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6905
- return this.githubSdk.getPrComments({
6906
- per_page: 100,
6907
- ...params,
6908
- owner,
6909
- repo
6910
- });
6911
- }
6912
- async getPrDiff(params) {
6913
- this._validateAccessTokenAndUrl();
6914
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6915
- const prRes = await this.githubSdk.getPrDiff({
6916
- ...params,
6917
- owner,
6918
- repo
6841
+ return gitlabValidateParams({
6842
+ url: this.url,
6843
+ accessToken: this.accessToken
6919
6844
  });
6920
- return z24.string().parse(prRes.data);
6921
6845
  }
6922
6846
  async getRepoList(_scmOrg) {
6923
- this._validateAccessToken();
6924
- return this.githubSdk.getGithubRepoList();
6847
+ if (!this.accessToken) {
6848
+ console.error("no access token");
6849
+ throw new Error("no access token");
6850
+ }
6851
+ return getGitlabRepoList(this.url, this.accessToken);
6925
6852
  }
6926
6853
  async getBranchList() {
6927
6854
  this._validateAccessTokenAndUrl();
6928
- const branches = await this.githubSdk.getGithubBranchList(this.url);
6929
- return branches.data.map((branch) => branch.name);
6855
+ return getGitlabBranchList({
6856
+ accessToken: this.accessToken,
6857
+ repoUrl: this.url
6858
+ });
6930
6859
  }
6931
6860
  get scmLibType() {
6932
- return "GITHUB" /* GITHUB */;
6861
+ return "GITLAB" /* GITLAB */;
6933
6862
  }
6934
6863
  getAuthHeaders() {
6935
- if (this.accessToken) {
6864
+ if (!this.accessToken) {
6865
+ return {};
6866
+ }
6867
+ if (this.accessToken.startsWith("glpat-")) {
6868
+ return {
6869
+ "Private-Token": this.accessToken
6870
+ };
6871
+ } else {
6936
6872
  return { authorization: `Bearer ${this.accessToken}` };
6937
6873
  }
6938
- return {};
6939
6874
  }
6940
6875
  getDownloadUrl(sha) {
6941
- this._validateUrl();
6942
- const res = parseScmURL(this.url, "GitHub" /* GitHub */);
6943
- if (!res) {
6944
- throw new InvalidRepoUrlError("invalid repo url");
6945
- }
6946
- const { protocol, hostname, organization, repoName } = res;
6947
- const downloadUrl = isGithubOnPrem(this.url) ? `${protocol}//${hostname}/api/v3/repos/${organization}/${repoName}/zipball/${sha}` : `https://api.${hostname}/repos/${organization}/${repoName}/zipball/${sha}`;
6948
- return Promise.resolve(downloadUrl);
6876
+ const urlObj = new URL(this.url || "");
6877
+ const ProjectId = encodeURIComponent(
6878
+ urlObj.pathname.replace(/^\//, "").replace(/\/$/, "")
6879
+ );
6880
+ return Promise.resolve(
6881
+ //We are moving away from this form as it doesn't work when using a non-human token (group/project token)
6882
+ //Where as the API zip endpoint works with any token
6883
+ //`${this.url}/-/archive/${sha}/${repoName}-${sha}.zip`
6884
+ `${urlObj.origin}/api/v4/projects/${ProjectId}/repository/archive.zip?sha=${sha}`
6885
+ );
6949
6886
  }
6950
6887
  async _getUsernameForAuthUrl() {
6951
- return this.getUsername();
6888
+ if (this?.accessToken?.startsWith("glpat-")) {
6889
+ return this.getUsername();
6890
+ } else {
6891
+ return "oauth2";
6892
+ }
6952
6893
  }
6953
6894
  async getIsRemoteBranch(branch) {
6954
- this._validateUrl();
6955
- return this.githubSdk.getGithubIsRemoteBranch({ branch, repoUrl: this.url });
6895
+ this._validateAccessTokenAndUrl();
6896
+ return getGitlabIsRemoteBranch({
6897
+ accessToken: this.accessToken,
6898
+ repoUrl: this.url,
6899
+ branch
6900
+ });
6956
6901
  }
6957
6902
  async getUserHasAccessToRepo() {
6958
6903
  this._validateAccessTokenAndUrl();
6959
- const username = await this.getUsername();
6960
- return this.githubSdk.getGithubIsUserCollaborator({
6961
- repoUrl: this.url,
6962
- username
6904
+ return getGitlabIsUserCollaborator({
6905
+ accessToken: this.accessToken,
6906
+ repoUrl: this.url
6963
6907
  });
6964
6908
  }
6965
6909
  async getUsername() {
6966
- this._validateAccessToken();
6967
- return this.githubSdk.getGithubUsername();
6910
+ this._validateAccessTokenAndUrl();
6911
+ return getGitlabUsername(this.url, this.accessToken);
6968
6912
  }
6969
6913
  async getSubmitRequestStatus(scmSubmitRequestId) {
6970
6914
  this._validateAccessTokenAndUrl();
6971
- return this.githubSdk.getGithubPullRequestStatus({
6915
+ const state = await getGitlabMergeRequestStatus({
6916
+ accessToken: this.accessToken,
6972
6917
  repoUrl: this.url,
6973
- prNumber: Number(scmSubmitRequestId)
6918
+ mrNumber: Number(scmSubmitRequestId)
6974
6919
  });
6920
+ switch (state) {
6921
+ case gitlabMergeRequestStatus.merged:
6922
+ return "merged";
6923
+ case gitlabMergeRequestStatus.opened:
6924
+ return "open";
6925
+ case gitlabMergeRequestStatus.closed:
6926
+ return "closed";
6927
+ default:
6928
+ throw new Error(`unknown state ${state}`);
6929
+ }
6975
6930
  }
6976
6931
  async addCommentToSubmitRequest(submitRequestId, comment) {
6977
6932
  this._validateAccessTokenAndUrl();
6978
- await this.githubSdk.createMarkdownCommentOnPullRequest({
6933
+ await createMarkdownCommentOnPullRequest({
6934
+ accessToken: this.accessToken,
6979
6935
  repoUrl: this.url,
6980
- prNumber: Number(submitRequestId),
6936
+ mrNumber: Number(submitRequestId),
6981
6937
  markdownComment: comment
6982
6938
  });
6983
6939
  }
6984
6940
  async getRepoBlameRanges(ref, path8) {
6985
6941
  this._validateUrl();
6986
- return await this.githubSdk.getGithubBlameRanges({
6987
- ref,
6988
- path: path8,
6989
- gitHubUrl: this.url
6990
- });
6942
+ return await getGitlabBlameRanges(
6943
+ { ref, path: path8, gitlabUrl: this.url },
6944
+ {
6945
+ url: this.url,
6946
+ gitlabAuthToken: this.accessToken
6947
+ }
6948
+ );
6991
6949
  }
6992
6950
  async getReferenceData(ref) {
6993
6951
  this._validateUrl();
6994
- return this.githubSdk.getGithubReferenceData({ ref, gitHubUrl: this.url });
6995
- }
6996
- async getPrComment(commentId) {
6997
- this._validateUrl();
6998
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6999
- return await this.githubSdk.getPrComment({
7000
- repo,
7001
- owner,
7002
- comment_id: commentId
7003
- });
6952
+ return await getGitlabReferenceData(
6953
+ { ref, gitlabUrl: this.url },
6954
+ {
6955
+ url: this.url,
6956
+ gitlabAuthToken: this.accessToken
6957
+ }
6958
+ );
7004
6959
  }
7005
6960
  async getRepoDefaultBranch() {
7006
6961
  this._validateUrl();
7007
- return await this.githubSdk.getGithubRepoDefaultBranch(this.url);
6962
+ return await getGitlabRepoDefaultBranch(this.url, {
6963
+ url: this.url,
6964
+ gitlabAuthToken: this.accessToken
6965
+ });
7008
6966
  }
7009
6967
  async getSubmitRequestUrl(submitRequestUrl) {
7010
6968
  this._validateAccessTokenAndUrl();
7011
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
7012
- const getPrRes = await this.githubSdk.getPr({
7013
- owner,
7014
- repo,
7015
- pull_number: submitRequestUrl
6969
+ const res = await getGitlabMergeRequest({
6970
+ url: this.url,
6971
+ prNumber: submitRequestUrl,
6972
+ accessToken: this.accessToken
7016
6973
  });
7017
- return getPrRes.data.html_url;
6974
+ return res.web_url;
7018
6975
  }
7019
6976
  async getSubmitRequestId(submitRequestUrl) {
7020
- const match = submitRequestUrl.match(/\/pull\/(\d+)/);
6977
+ const match = submitRequestUrl.match(/\/merge_requests\/(\d+)/);
7021
6978
  return match?.[1] || "";
7022
6979
  }
7023
6980
  async getCommitUrl(commitId) {
7024
6981
  this._validateAccessTokenAndUrl();
7025
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
7026
- const getCommitRes = await this.githubSdk.getCommit({
7027
- owner,
7028
- repo,
7029
- commitSha: commitId
6982
+ const res = await getGitlabCommitUrl({
6983
+ url: this.url,
6984
+ commitSha: commitId,
6985
+ accessToken: this.accessToken
7030
6986
  });
7031
- return getCommitRes.data.html_url;
6987
+ return res.web_url;
7032
6988
  }
7033
- async postGeneralPrComment(params) {
7034
- const { prNumber, body } = params;
7035
- this._validateAccessTokenAndUrl();
7036
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
7037
- return await this.githubSdk.postGeneralPrComment({
7038
- issue_number: prNumber,
7039
- owner,
7040
- repo,
7041
- body
7042
- });
6989
+ };
6990
+
6991
+ // src/features/analysis/scm/scmFactory.ts
6992
+ import { z as z24 } from "zod";
6993
+
6994
+ // src/features/analysis/scm/StubSCMLib.ts
6995
+ var StubSCMLib = class extends SCMLib {
6996
+ constructor(url, accessToken, scmOrg) {
6997
+ super(url, accessToken, scmOrg);
7043
6998
  }
7044
- async getGeneralPrComments(params) {
7045
- const { prNumber } = params;
7046
- this._validateAccessTokenAndUrl();
7047
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
7048
- return await this.githubSdk.getGeneralPrComments({
7049
- issue_number: prNumber,
7050
- owner,
7051
- repo
7052
- });
6999
+ async getUrlWithCredentials() {
7000
+ console.warn("getUrlWithCredentials() returning empty string");
7001
+ return "";
7053
7002
  }
7054
- async deleteGeneralPrComment({
7055
- commentId
7056
- }) {
7057
- this._validateAccessTokenAndUrl();
7058
- const { owner, repo } = parseGithubOwnerAndRepo(this.url);
7059
- return this.githubSdk.deleteGeneralPrComment({
7060
- owner,
7061
- repo,
7062
- comment_id: commentId
7063
- });
7003
+ async createSubmitRequest(_params) {
7004
+ console.warn("createSubmitRequest() returning empty string");
7005
+ return "";
7006
+ }
7007
+ get scmLibType() {
7008
+ console.warn("scmLibType returning GITHUB as default");
7009
+ return "GITHUB" /* GITHUB */;
7010
+ }
7011
+ getAuthHeaders() {
7012
+ console.warn("getAuthHeaders() returning empty object");
7013
+ return {};
7014
+ }
7015
+ async getDownloadUrl(_sha) {
7016
+ console.warn("getDownloadUrl() returning empty string");
7017
+ return "";
7018
+ }
7019
+ async getIsRemoteBranch(_branch) {
7020
+ console.warn("getIsRemoteBranch() returning false");
7021
+ return false;
7022
+ }
7023
+ async validateParams() {
7024
+ console.warn("validateParams() no-op");
7025
+ }
7026
+ async getRepoList(_scmOrg) {
7027
+ console.warn("getRepoList() returning empty array");
7028
+ return [];
7029
+ }
7030
+ async getBranchList() {
7031
+ console.warn("getBranchList() returning empty array");
7032
+ return [];
7033
+ }
7034
+ async getUsername() {
7035
+ console.warn("getUsername() returning empty string");
7036
+ return "";
7037
+ }
7038
+ async getSubmitRequestStatus(_scmSubmitRequestId) {
7039
+ console.warn("getSubmitRequestStatus() returning ERROR");
7040
+ return "error";
7041
+ }
7042
+ async getUserHasAccessToRepo() {
7043
+ console.warn("getUserHasAccessToRepo() returning false");
7044
+ return false;
7045
+ }
7046
+ async getRepoBlameRanges(_ref, _path) {
7047
+ console.warn("getRepoBlameRanges() returning empty array");
7048
+ return [];
7049
+ }
7050
+ async getReferenceData(_ref) {
7051
+ console.warn("getReferenceData() returning null/empty defaults");
7052
+ return {
7053
+ type: "BRANCH" /* BRANCH */,
7054
+ sha: "",
7055
+ date: void 0
7056
+ };
7057
+ }
7058
+ async getRepoDefaultBranch() {
7059
+ console.warn("getRepoDefaultBranch() returning empty string");
7060
+ return "";
7061
+ }
7062
+ async getSubmitRequestUrl(_submitRequestIdNumber) {
7063
+ console.warn("getSubmitRequestUrl() returning empty string");
7064
+ return "";
7065
+ }
7066
+ async getSubmitRequestId(_submitRequestUrl) {
7067
+ console.warn("getSubmitRequestId() returning empty string");
7068
+ return "";
7069
+ }
7070
+ async getCommitUrl(_commitId) {
7071
+ console.warn("getCommitUrl() returning empty string");
7072
+ return "";
7073
+ }
7074
+ async _getUsernameForAuthUrl() {
7075
+ console.warn("_getUsernameForAuthUrl() returning empty string");
7076
+ return "";
7077
+ }
7078
+ async addCommentToSubmitRequest(_submitRequestId, _comment) {
7079
+ console.warn("addCommentToSubmitRequest() no-op");
7064
7080
  }
7065
7081
  };
7066
7082
 
7083
+ // src/features/analysis/scm/scmFactory.ts
7084
+ async function createScmLib({ url, accessToken, scmType, scmOrg }, { propagateExceptions = false } = {}) {
7085
+ const trimmedUrl = url ? url.trim().replace(/\/$/, "").replace(/.git$/i, "") : void 0;
7086
+ try {
7087
+ switch (scmType) {
7088
+ case "GITHUB" /* GITHUB */: {
7089
+ const scm = new GithubSCMLib(trimmedUrl, accessToken, scmOrg);
7090
+ await scm.validateParams();
7091
+ return scm;
7092
+ }
7093
+ case "GITLAB" /* GITLAB */: {
7094
+ const scm = new GitlabSCMLib(trimmedUrl, accessToken, scmOrg);
7095
+ await scm.validateParams();
7096
+ return scm;
7097
+ }
7098
+ case "ADO" /* ADO */: {
7099
+ const scm = new AdoSCMLib(trimmedUrl, accessToken, scmOrg);
7100
+ await scm.getAdoSdk();
7101
+ await scm.validateParams();
7102
+ return scm;
7103
+ }
7104
+ case "BITBUCKET" /* BITBUCKET */: {
7105
+ const scm = new BitbucketSCMLib(trimmedUrl, accessToken, scmOrg);
7106
+ await scm.validateParams();
7107
+ return scm;
7108
+ }
7109
+ }
7110
+ } catch (e) {
7111
+ if (e instanceof InvalidRepoUrlError && url) {
7112
+ throw new RepoNoTokenAccessError(
7113
+ "no access to repo",
7114
+ scmLibScmTypeToScmType[z24.nativeEnum(ScmLibScmType).parse(scmType)]
7115
+ );
7116
+ }
7117
+ console.error(`error validating scm: ${scmType} `, e);
7118
+ if (propagateExceptions) {
7119
+ throw e;
7120
+ }
7121
+ }
7122
+ return new StubSCMLib(trimmedUrl, void 0, void 0);
7123
+ }
7124
+
7067
7125
  // src/features/analysis/add_fix_comments_for_pr/utils/utils.ts
7068
7126
  import Debug7 from "debug";
7069
7127
  import parseDiff from "parse-diff";
@@ -7238,7 +7296,8 @@ function buildIssueCommentBody({
7238
7296
  projectId,
7239
7297
  analysisId,
7240
7298
  organizationId,
7241
- irrelevantIssueWithTags
7299
+ irrelevantIssueWithTags,
7300
+ fpDescription
7242
7301
  }) {
7243
7302
  const issueUrl = getIssueUrlWithRedirect({
7244
7303
  appBaseUrl: WEB_APP_URL,
@@ -7253,9 +7312,10 @@ function buildIssueCommentBody({
7253
7312
  const subTitle = getCommitIssueDescription({
7254
7313
  issueType,
7255
7314
  vendor: scannerToVulnerability_Report_Vendor_Enum[scanner],
7256
- irrelevantIssueWithTags
7315
+ irrelevantIssueWithTags,
7316
+ fpDescription
7257
7317
  });
7258
- const issuePageLink = `[Learn more and fine tune the issue](${issueUrl})`;
7318
+ const issuePageLink = `[Learn more about this issue](${issueUrl})`;
7259
7319
  return `${title}
7260
7320
  ${subTitle}
7261
7321
  ${issuePageLink}`;
@@ -7326,7 +7386,8 @@ async function postIssueComment(params) {
7326
7386
  scm,
7327
7387
  commitSha,
7328
7388
  pullRequest,
7329
- scanner
7389
+ scanner,
7390
+ fpDescription
7330
7391
  } = params;
7331
7392
  const {
7332
7393
  path: path8,
@@ -7357,7 +7418,8 @@ Refresh the page in order to see the changes.`,
7357
7418
  scanner,
7358
7419
  projectId,
7359
7420
  analysisId,
7360
- organizationId
7421
+ organizationId,
7422
+ fpDescription
7361
7423
  });
7362
7424
  return await scm.updatePrComment({
7363
7425
  body: commentBody,
@@ -7570,33 +7632,49 @@ async function addFixCommentsForPr({
7570
7632
  });
7571
7633
  }
7572
7634
  ),
7573
- ...irrelevantVulnerabilityReportIssues.map((vulnerabilityReportIssue) => {
7574
- return vulnerabilityReportIssue.codeNodes.map(
7575
- (vulnerabilityReportIssueCodeNode) => {
7576
- return postIssueComment({
7577
- vulnerabilityReportIssueCodeNode: {
7578
- path: vulnerabilityReportIssueCodeNode.path,
7579
- startLine: vulnerabilityReportIssueCodeNode.startLine,
7580
- vulnerabilityReportIssue: {
7581
- fixId: "",
7582
- safeIssueType: vulnerabilityReportIssue.safeIssueType,
7583
- vulnerabilityReportIssueTags: vulnerabilityReportIssue.vulnerabilityReportIssueTags,
7584
- category: vulnerabilityReportIssue.category
7585
- },
7586
- vulnerabilityReportIssueId: vulnerabilityReportIssue.id
7587
- },
7588
- projectId,
7589
- analysisId,
7590
- organizationId,
7591
- fixesById,
7592
- scm,
7593
- pullRequest,
7594
- scanner,
7595
- commitSha
7635
+ ...irrelevantVulnerabilityReportIssues.map(
7636
+ async (vulnerabilityReportIssue) => {
7637
+ let fpDescription = null;
7638
+ if (vulnerabilityReportIssue.fpId) {
7639
+ const fpRes = await gqlClient.getFalsePositive({
7640
+ fpId: vulnerabilityReportIssue.fpId
7596
7641
  });
7642
+ const parsedFpRes = await FalsePositivePartsZ.parseAsync(
7643
+ fpRes?.getFalsePositive
7644
+ );
7645
+ const { description, contextString } = getParsedFalsePositiveMessage(parsedFpRes);
7646
+ fpDescription = contextString ? `${description}
7647
+
7648
+ ${contextString}` : description;
7597
7649
  }
7598
- );
7599
- }),
7650
+ return vulnerabilityReportIssue.codeNodes.map(
7651
+ (vulnerabilityReportIssueCodeNode) => {
7652
+ return postIssueComment({
7653
+ vulnerabilityReportIssueCodeNode: {
7654
+ path: vulnerabilityReportIssueCodeNode.path,
7655
+ startLine: vulnerabilityReportIssueCodeNode.startLine,
7656
+ vulnerabilityReportIssue: {
7657
+ fixId: "",
7658
+ safeIssueType: vulnerabilityReportIssue.safeIssueType,
7659
+ vulnerabilityReportIssueTags: vulnerabilityReportIssue.vulnerabilityReportIssueTags,
7660
+ category: vulnerabilityReportIssue.category
7661
+ },
7662
+ vulnerabilityReportIssueId: vulnerabilityReportIssue.id
7663
+ },
7664
+ projectId,
7665
+ analysisId,
7666
+ organizationId,
7667
+ fixesById,
7668
+ scm,
7669
+ pullRequest,
7670
+ scanner,
7671
+ commitSha,
7672
+ fpDescription
7673
+ });
7674
+ }
7675
+ );
7676
+ }
7677
+ ),
7600
7678
  postAnalysisInsightComment({
7601
7679
  prVulenrabilities,
7602
7680
  pullRequest,
@@ -7827,6 +7905,7 @@ var VulnerabilityReportIssueNoFixCodeNodeZ = z27.object({
7827
7905
  fixId: z27.string().nullable(),
7828
7906
  category: ValidCategoriesZ,
7829
7907
  safeIssueType: z27.string(),
7908
+ fpId: z27.string().uuid().nullable(),
7830
7909
  codeNodes: z27.array(
7831
7910
  z27.object({
7832
7911
  path: z27.string(),
@@ -8190,6 +8269,9 @@ var GQLClient = class {
8190
8269
  async getReferenceData(args) {
8191
8270
  return this._clientSdk.gitReference(args);
8192
8271
  }
8272
+ async getFalsePositive(args) {
8273
+ return this._clientSdk.getFalsePositive(args);
8274
+ }
8193
8275
  };
8194
8276
 
8195
8277
  // src/features/analysis/pack.ts