mobbdev 1.0.67 → 1.0.74

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