mobbdev 0.0.85 → 0.0.87

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 +87 -33
  2. package/package.json +2 -1
package/dist/index.mjs CHANGED
@@ -1085,7 +1085,7 @@ import { Octokit } from "octokit";
1085
1085
  import { z as z3 } from "zod";
1086
1086
 
1087
1087
  // src/features/analysis/scm/urlParser.ts
1088
- function getRepoInfo(pathname, hostname) {
1088
+ function getRepoInfo(pathname, hostname, scmType) {
1089
1089
  const hostnameParts = hostname.split(".");
1090
1090
  if (hostnameParts.length === 3 && hostnameParts[1] === "visualstudio" && hostnameParts[2] === "com") {
1091
1091
  if (pathname.length === 2 && pathname[0] === "_git") {
@@ -1103,7 +1103,7 @@ function getRepoInfo(pathname, hostname) {
1103
1103
  };
1104
1104
  }
1105
1105
  }
1106
- if (hostname === "dev.azure.com") {
1106
+ if (hostname === "dev.azure.com" || scmType === "Ado" /* Ado */) {
1107
1107
  if (pathname.length === 3 && pathname[1] === "_git") {
1108
1108
  return {
1109
1109
  organization: pathname[0],
@@ -1119,7 +1119,7 @@ function getRepoInfo(pathname, hostname) {
1119
1119
  };
1120
1120
  }
1121
1121
  }
1122
- if (hostname === "github.com") {
1122
+ if (hostname === "github.com" || scmType === "GitHub" /* GitHub */) {
1123
1123
  if (pathname.length === 2) {
1124
1124
  return {
1125
1125
  organization: pathname[0],
@@ -1128,7 +1128,7 @@ function getRepoInfo(pathname, hostname) {
1128
1128
  };
1129
1129
  }
1130
1130
  }
1131
- if (hostname === "gitlab.com") {
1131
+ if (hostname === "gitlab.com" || scmType === "GitLab" /* GitLab */) {
1132
1132
  if (pathname.length >= 2) {
1133
1133
  return {
1134
1134
  organization: pathname[0],
@@ -1140,12 +1140,12 @@ function getRepoInfo(pathname, hostname) {
1140
1140
  return null;
1141
1141
  }
1142
1142
  var NAME_REGEX = /[a-z0-9\-_.+]+/i;
1143
- var parseScmURL = (scmURL) => {
1143
+ var parseScmURL = (scmURL, scmType) => {
1144
1144
  try {
1145
1145
  const url = new URL(scmURL);
1146
1146
  const hostname = url.hostname.toLowerCase();
1147
1147
  const projectPath = url.pathname.substring(1).replace(/.git$/i, "");
1148
- const repo = getRepoInfo(projectPath.split("/"), hostname);
1148
+ const repo = getRepoInfo(projectPath.split("/"), hostname, scmType);
1149
1149
  if (!repo)
1150
1150
  return null;
1151
1151
  const { organization, repoName, projectName } = repo;
@@ -1165,6 +1165,22 @@ var parseScmURL = (scmURL) => {
1165
1165
  return null;
1166
1166
  }
1167
1167
  };
1168
+ var sanityRepoURL = (scmURL) => {
1169
+ try {
1170
+ const url = new URL(scmURL);
1171
+ const projectPath = url.pathname.substring(1).replace(/.git$/i, "");
1172
+ const pathParts = projectPath.split("/");
1173
+ if (pathParts.length < 2)
1174
+ return false;
1175
+ if (pathParts.length > 4)
1176
+ return false;
1177
+ if (pathParts.some((part) => !part.match(NAME_REGEX)))
1178
+ return false;
1179
+ return true;
1180
+ } catch (e) {
1181
+ return null;
1182
+ }
1183
+ };
1168
1184
 
1169
1185
  // src/features/analysis/scm/github/github.ts
1170
1186
  function removeTrailingSlash(str) {
@@ -1445,7 +1461,7 @@ async function getCommit({
1445
1461
  }
1446
1462
  function parseGithubOwnerAndRepo(gitHubUrl) {
1447
1463
  gitHubUrl = removeTrailingSlash(gitHubUrl);
1448
- const parsingResult = parseScmURL(gitHubUrl);
1464
+ const parsingResult = parseScmURL(gitHubUrl, "GitHub" /* GitHub */);
1449
1465
  if (!parsingResult || parsingResult.hostname !== "github.com") {
1450
1466
  throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
1451
1467
  }
@@ -1650,6 +1666,7 @@ function deleteGeneralPrComment(client, params) {
1650
1666
  // src/features/analysis/scm/gitlab.ts
1651
1667
  import querystring from "node:querystring";
1652
1668
  import { Gitlab } from "@gitbeaker/rest";
1669
+ import { ProxyAgent } from "undici";
1653
1670
  import { z as z4 } from "zod";
1654
1671
  function removeTrailingSlash2(str) {
1655
1672
  return str.trim().replace(/\/+$/, "");
@@ -1660,17 +1677,19 @@ var EnvVariablesZod2 = z4.object({
1660
1677
  var { GITLAB_API_TOKEN } = EnvVariablesZod2.parse(process.env);
1661
1678
  function getGitBeaker(options) {
1662
1679
  const token = options?.gitlabAuthToken ?? GITLAB_API_TOKEN ?? "";
1680
+ const url = options.url;
1681
+ const host = url ? new URL(url).origin : "https://gitlab.com";
1663
1682
  if (token?.startsWith("glpat-") || token === "") {
1664
- return new Gitlab({ token });
1683
+ return new Gitlab({ token, host });
1665
1684
  }
1666
- return new Gitlab({ oauthToken: token });
1685
+ return new Gitlab({ oauthToken: token, host });
1667
1686
  }
1668
1687
  async function gitlabValidateParams({
1669
1688
  url,
1670
1689
  accessToken
1671
1690
  }) {
1672
1691
  try {
1673
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1692
+ const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
1674
1693
  if (accessToken) {
1675
1694
  await api2.Users.showCurrentUser();
1676
1695
  }
@@ -1691,8 +1710,8 @@ async function gitlabValidateParams({
1691
1710
  throw e;
1692
1711
  }
1693
1712
  }
1694
- async function getGitlabUsername(accessToken) {
1695
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1713
+ async function getGitlabUsername(url, accessToken) {
1714
+ const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
1696
1715
  const res = await api2.Users.showCurrentUser();
1697
1716
  return res.username;
1698
1717
  }
@@ -1703,7 +1722,7 @@ async function getGitlabIsUserCollaborator({
1703
1722
  }) {
1704
1723
  try {
1705
1724
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
1706
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1725
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
1707
1726
  const res = await api2.Projects.show(projectPath);
1708
1727
  const members = await api2.ProjectMembers.all(res.id, {
1709
1728
  includeInherited: true
@@ -1719,7 +1738,7 @@ async function getGitlabMergeRequestStatus({
1719
1738
  mrNumber
1720
1739
  }) {
1721
1740
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
1722
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1741
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
1723
1742
  const res = await api2.MergeRequests.show(projectPath, mrNumber);
1724
1743
  switch (res.state) {
1725
1744
  case "merged" /* merged */:
@@ -1736,7 +1755,7 @@ async function getGitlabIsRemoteBranch({
1736
1755
  branch
1737
1756
  }) {
1738
1757
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
1739
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1758
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
1740
1759
  try {
1741
1760
  const res = await api2.Branches.show(projectPath, branch);
1742
1761
  return res.name === branch;
@@ -1744,8 +1763,8 @@ async function getGitlabIsRemoteBranch({
1744
1763
  return false;
1745
1764
  }
1746
1765
  }
1747
- async function getGitlabRepoList(accessToken) {
1748
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1766
+ async function getGitlabRepoList(url, accessToken) {
1767
+ const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
1749
1768
  const res = await api2.Projects.all({
1750
1769
  membership: true,
1751
1770
  //TODO: a bug in the sorting mechanism of this api call
@@ -1778,7 +1797,7 @@ async function getGitlabBranchList({
1778
1797
  repoUrl
1779
1798
  }) {
1780
1799
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
1781
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1800
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
1782
1801
  try {
1783
1802
  const res = await api2.Branches.all(projectPath, {
1784
1803
  perPage: 100,
@@ -1793,7 +1812,10 @@ async function getGitlabBranchList({
1793
1812
  }
1794
1813
  async function createMergeRequest(options) {
1795
1814
  const { projectPath } = parseGitlabOwnerAndRepo(options.repoUrl);
1796
- const api2 = getGitBeaker({ gitlabAuthToken: options.accessToken });
1815
+ const api2 = getGitBeaker({
1816
+ url: options.repoUrl,
1817
+ gitlabAuthToken: options.accessToken
1818
+ });
1797
1819
  const res = await api2.MergeRequests.create(
1798
1820
  projectPath,
1799
1821
  options.sourceBranchName,
@@ -1806,7 +1828,10 @@ async function createMergeRequest(options) {
1806
1828
  return res.iid;
1807
1829
  }
1808
1830
  async function getGitlabRepoDefaultBranch(repoUrl, options) {
1809
- const api2 = getGitBeaker({ gitlabAuthToken: options?.gitlabAuthToken });
1831
+ const api2 = getGitBeaker({
1832
+ url: repoUrl,
1833
+ gitlabAuthToken: options?.gitlabAuthToken
1834
+ });
1810
1835
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
1811
1836
  const project = await api2.Projects.show(projectPath);
1812
1837
  if (!project.default_branch) {
@@ -1816,7 +1841,10 @@ async function getGitlabRepoDefaultBranch(repoUrl, options) {
1816
1841
  }
1817
1842
  async function getGitlabReferenceData({ ref, gitlabUrl }, options) {
1818
1843
  const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
1819
- const api2 = getGitBeaker({ gitlabAuthToken: options?.gitlabAuthToken });
1844
+ const api2 = getGitBeaker({
1845
+ url: gitlabUrl,
1846
+ gitlabAuthToken: options?.gitlabAuthToken
1847
+ });
1820
1848
  const results = await Promise.allSettled([
1821
1849
  (async () => {
1822
1850
  const res = await api2.Branches.show(projectPath, ref);
@@ -1857,8 +1885,8 @@ async function getGitlabReferenceData({ ref, gitlabUrl }, options) {
1857
1885
  }
1858
1886
  function parseGitlabOwnerAndRepo(gitlabUrl) {
1859
1887
  gitlabUrl = removeTrailingSlash2(gitlabUrl);
1860
- const parsingResult = parseScmURL(gitlabUrl);
1861
- if (!parsingResult || parsingResult.hostname !== "gitlab.com") {
1888
+ const parsingResult = parseScmURL(gitlabUrl, "GitLab" /* GitLab */);
1889
+ if (!parsingResult || !parsingResult.repoName) {
1862
1890
  throw new InvalidUrlPatternError(`invalid gitlab repo Url ${gitlabUrl}`);
1863
1891
  }
1864
1892
  const { organization, repoName, projectPath } = parsingResult;
@@ -1866,7 +1894,10 @@ function parseGitlabOwnerAndRepo(gitlabUrl) {
1866
1894
  }
1867
1895
  async function getGitlabBlameRanges({ ref, gitlabUrl, path: path9 }, options) {
1868
1896
  const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
1869
- const api2 = getGitBeaker({ gitlabAuthToken: options?.gitlabAuthToken });
1897
+ const api2 = getGitBeaker({
1898
+ url: gitlabUrl,
1899
+ gitlabAuthToken: options?.gitlabAuthToken
1900
+ });
1870
1901
  const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path9, ref);
1871
1902
  let lineNumber = 1;
1872
1903
  return resp.filter((range) => range.lines).map((range) => {
@@ -1889,6 +1920,24 @@ var GitlabAuthResultZ = z4.object({
1889
1920
  token_type: z4.string(),
1890
1921
  refresh_token: z4.string()
1891
1922
  });
1923
+ function initGitlabFetchMock() {
1924
+ const globalFetch = global.fetch;
1925
+ function myFetch(input, init) {
1926
+ const stack = new Error().stack;
1927
+ const parts = stack?.split("at ");
1928
+ if (parts?.length && parts?.length >= 3 && parts[2]?.startsWith("defaultRequestHandler (") && parts[2]?.includes("/@gitbeaker/rest/dist/index.js") && (/^https?:\/\/[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\//i.test(
1929
+ input?.url
1930
+ ) || "GITLAB_INTERNAL_DEV_HOST" in process.env && process.env["GITLAB_INTERNAL_DEV_HOST"] && input?.url?.startsWith(process.env["GITLAB_INTERNAL_DEV_HOST"]))) {
1931
+ const dispatcher = new ProxyAgent(
1932
+ process.env["GIT_PROXY_HOST"] || "http://tinyproxy:8888"
1933
+ );
1934
+ return globalFetch(input, { dispatcher });
1935
+ }
1936
+ return globalFetch(input, init);
1937
+ }
1938
+ global.fetch = myFetch;
1939
+ }
1940
+ initGitlabFetchMock();
1892
1941
 
1893
1942
  // src/features/analysis/scm/scmSubmit/index.ts
1894
1943
  import fs from "node:fs/promises";
@@ -1992,7 +2041,7 @@ function getCloudScmLibTypeFromUrl(url) {
1992
2041
  return void 0;
1993
2042
  }
1994
2043
  const urlObject = new URL(url);
1995
- const hostname = urlObject.hostname;
2044
+ const hostname = urlObject.hostname.toLowerCase();
1996
2045
  if (hostname === "gitlab.com") {
1997
2046
  return "GITLAB" /* GITLAB */;
1998
2047
  }
@@ -2040,7 +2089,7 @@ function getScmConfig({
2040
2089
  //if we the user does an ADO oauth flow then the token is saved for dev.azure.com but
2041
2090
  //sometimes the user uses the url dev.azure.com and sometimes the url visualstudio.com
2042
2091
  //so we need to check both
2043
- (urlObject.hostname === configUrl.hostname || urlObject.hostname.endsWith(".visualstudio.com") && configUrl.hostname === "dev.azure.com") && urlObject.protocol === configUrl.protocol && urlObject.port === configUrl.port
2092
+ (urlObject.hostname.toLowerCase() === configUrl.hostname.toLowerCase() || urlObject.hostname.toLowerCase().endsWith(".visualstudio.com") && configUrl.hostname.toLowerCase() === "dev.azure.com") && urlObject.protocol === configUrl.protocol && urlObject.port === configUrl.port
2044
2093
  );
2045
2094
  });
2046
2095
  const scmOrgConfig = filteredScmConfigs.find((scm) => scm.orgId && scm.token);
@@ -2428,7 +2477,7 @@ var GitlabSCMLib = class extends SCMLib {
2428
2477
  console.error("no access token");
2429
2478
  throw new Error("no access token");
2430
2479
  }
2431
- return getGitlabRepoList(this.accessToken);
2480
+ return getGitlabRepoList(this.url, this.accessToken);
2432
2481
  }
2433
2482
  async getBranchList() {
2434
2483
  if (!this.accessToken || !this.url) {
@@ -2491,7 +2540,7 @@ var GitlabSCMLib = class extends SCMLib {
2491
2540
  console.error("no access token");
2492
2541
  throw new Error("no access token");
2493
2542
  }
2494
- return getGitlabUsername(this.accessToken);
2543
+ return getGitlabUsername(this.url, this.accessToken);
2495
2544
  }
2496
2545
  async getSubmitRequestStatus(scmSubmitRequestId) {
2497
2546
  if (!this.accessToken || !this.url) {
@@ -2522,6 +2571,7 @@ var GitlabSCMLib = class extends SCMLib {
2522
2571
  return await getGitlabBlameRanges(
2523
2572
  { ref, path: path9, gitlabUrl: this.url },
2524
2573
  {
2574
+ url: this.url,
2525
2575
  gitlabAuthToken: this.accessToken
2526
2576
  }
2527
2577
  );
@@ -2534,6 +2584,7 @@ var GitlabSCMLib = class extends SCMLib {
2534
2584
  return await getGitlabReferenceData(
2535
2585
  { ref, gitlabUrl: this.url },
2536
2586
  {
2587
+ url: this.url,
2537
2588
  gitlabAuthToken: this.accessToken
2538
2589
  }
2539
2590
  );
@@ -2544,6 +2595,7 @@ var GitlabSCMLib = class extends SCMLib {
2544
2595
  throw new Error("no url");
2545
2596
  }
2546
2597
  return await getGitlabRepoDefaultBranch(this.url, {
2598
+ url: this.url,
2547
2599
  gitlabAuthToken: this.accessToken
2548
2600
  });
2549
2601
  }
@@ -3228,7 +3280,9 @@ function getAdoDownloadUrl({
3228
3280
  branch
3229
3281
  }) {
3230
3282
  const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
3231
- return `https://dev.azure.com/${owner}/${projectName}/_apis/git/repositories/${repo}/items/items?path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
3283
+ const url = new URL(repoUrl);
3284
+ const origin = url.origin.toLowerCase().endsWith(".visualstudio.com") ? "https://dev.azure.com" : url.origin.toLowerCase();
3285
+ return `${origin}/${owner}/${projectName}/_apis/git/repositories/${repo}/items/items?path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
3232
3286
  }
3233
3287
  async function getAdoBranchList({
3234
3288
  accessToken,
@@ -3398,7 +3452,7 @@ async function getAdoReferenceData({
3398
3452
  }
3399
3453
  function parseAdoOwnerAndRepo(adoUrl) {
3400
3454
  adoUrl = removeTrailingSlash3(adoUrl);
3401
- const parsingResult = parseScmURL(adoUrl);
3455
+ const parsingResult = parseScmURL(adoUrl, "Ado" /* Ado */);
3402
3456
  if (!parsingResult || parsingResult.hostname !== "dev.azure.com" && !parsingResult.hostname.endsWith(".visualstudio.com")) {
3403
3457
  throw new InvalidUrlPatternError(`invalid ADO repo URL: ${adoUrl}`);
3404
3458
  }
@@ -4938,7 +4992,7 @@ Example:
4938
4992
  }
4939
4993
  var UrlZ = z11.string({
4940
4994
  invalid_type_error: "is not a valid GitHub / GitLab / ADO URL"
4941
- }).refine((data) => !!parseScmURL(data), {
4995
+ }).refine((data) => !!sanityRepoURL(data), {
4942
4996
  message: "is not a valid GitHub / GitLab / ADO URL"
4943
4997
  });
4944
4998
  function validateRepoUrl(args) {
@@ -5103,10 +5157,10 @@ function validateAddScmTokenOptions(argv) {
5103
5157
  );
5104
5158
  }
5105
5159
  const urlObj = new URL(argv.url);
5106
- if (urlObj.hostname === "github.com" && !argv.username) {
5160
+ if (urlObj.hostname.toLowerCase() === "github.com" && !argv.username) {
5107
5161
  throw new CliError("\nError: --username flag is required for GitHub");
5108
5162
  }
5109
- if ((urlObj.hostname === "dev.azure.com" || urlObj.hostname.endsWith(".visualstudio.com")) && !argv.organization) {
5163
+ if ((urlObj.hostname.toLowerCase() === "dev.azure.com" || urlObj.hostname.toLowerCase().endsWith(".visualstudio.com")) && !argv.organization) {
5110
5164
  throw new CliError(
5111
5165
  "\nError: --organization flag is required for Azure DevOps"
5112
5166
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "0.0.85",
3
+ "version": "0.0.87",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "https://github.com/mobb-dev/bugsy",
6
6
  "main": "dist/index.js",
@@ -58,6 +58,7 @@
58
58
  "supports-color": "9.4.0",
59
59
  "tar": "6.2.0",
60
60
  "tmp": "0.2.1",
61
+ "undici": "6.7.0",
61
62
  "uuid": "9.0.1",
62
63
  "ws": "8.10.0",
63
64
  "yargs": "17.7.2",