mobbdev 0.0.67 → 0.0.69

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 +347 -94
  2. package/package.json +3 -1
package/dist/index.mjs CHANGED
@@ -163,7 +163,7 @@ import fetch3 from "node-fetch";
163
163
  import open2 from "open";
164
164
  import semver from "semver";
165
165
  import tmp2 from "tmp";
166
- import { z as z7 } from "zod";
166
+ import { z as z9 } from "zod";
167
167
 
168
168
  // src/features/analysis/git.ts
169
169
  import Debug2 from "debug";
@@ -274,6 +274,7 @@ var SUBMIT_VULNERABILITY_REPORT = gql`
274
274
  $reference: String!
275
275
  $projectId: String!
276
276
  $sha: String
277
+ $experimentalEnabled: Boolean
277
278
  $vulnerabilityReportFileName: String
278
279
  $pullRequest: Int
279
280
  ) {
@@ -282,6 +283,7 @@ var SUBMIT_VULNERABILITY_REPORT = gql`
282
283
  repoUrl: $repoUrl
283
284
  reference: $reference
284
285
  sha: $sha
286
+ experimentalEnabled: $experimentalEnabled
285
287
  pullRequest: $pullRequest
286
288
  projectId: $projectId
287
289
  vulnerabilityReportFileName: $vulnerabilityReportFileName
@@ -762,6 +764,7 @@ var GQLClient = class {
762
764
  const filters = hunks.map((hunk) => {
763
765
  const filter = {
764
766
  path: { _eq: hunk.path },
767
+ vulnerabilityReportIssue: { fixId: { _is_null: false } },
765
768
  _or: hunk.ranges.map(({ endLine, startLine }) => ({
766
769
  startLine: { _gte: startLine, _lte: endLine },
767
770
  endLine: { _gte: startLine, _lte: endLine }
@@ -812,6 +815,7 @@ var GQLClient = class {
812
815
  reference,
813
816
  projectId,
814
817
  sha,
818
+ experimentalEnabled,
815
819
  vulnerabilityReportFileName,
816
820
  pullRequest
817
821
  } = params;
@@ -822,7 +826,8 @@ var GQLClient = class {
822
826
  vulnerabilityReportFileName,
823
827
  projectId,
824
828
  pullRequest,
825
- sha: sha || ""
829
+ sha: sha || "",
830
+ experimentalEnabled
826
831
  });
827
832
  return CreateUpdateFixReportMutationZ.parse(res);
828
833
  }
@@ -897,15 +902,30 @@ var GQLClient = class {
897
902
  // src/features/analysis/handle_finished_analysis.ts
898
903
  import Debug4 from "debug";
899
904
  import parseDiff from "parse-diff";
900
- import { z as z6 } from "zod";
905
+ import { z as z8 } from "zod";
906
+
907
+ // src/features/analysis/scm/constants.ts
908
+ var MOBB_ICON_IMG = "https://app.mobb.ai/mobb.png";
909
+ var COMMIT_FIX_SVG = `https://app.mobb.ai/gh-action/commit-button.svg`;
901
910
 
902
911
  // src/features/analysis/scm/gitlab.ts
903
912
  import querystring from "node:querystring";
904
913
  import { Gitlab } from "@gitbeaker/rest";
905
- import { z as z5 } from "zod";
914
+ import { z as z7 } from "zod";
906
915
 
907
916
  // src/features/analysis/scm/scm.ts
908
917
  import { Octokit as Octokit2 } from "@octokit/core";
918
+ import { z as z6 } from "zod";
919
+
920
+ // src/features/analysis/scm/github/encryptSecret.ts
921
+ import sodium from "libsodium-wrappers";
922
+ async function encryptSecret(secret, key) {
923
+ await sodium.ready;
924
+ const binkey = sodium.from_base64(key, sodium.base64_variants.ORIGINAL);
925
+ const binsec = sodium.from_string(secret);
926
+ const encBytes = sodium.crypto_box_seal(binsec, binkey);
927
+ return sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL);
928
+ }
909
929
 
910
930
  // src/features/analysis/scm/github/github.ts
911
931
  import { RequestError } from "@octokit/request-error";
@@ -1137,6 +1157,16 @@ async function createPullRequest(options) {
1137
1157
  });
1138
1158
  return res.data.number;
1139
1159
  }
1160
+ async function forkRepo(options) {
1161
+ const { owner, repo } = parseOwnerAndRepo(options.repoUrl);
1162
+ const oktoKit = getOktoKit({ githubAuthToken: options.accessToken });
1163
+ const res = await oktoKit.rest.repos.createFork({
1164
+ owner,
1165
+ repo,
1166
+ default_branch_only: false
1167
+ });
1168
+ return { url: res.data.html_url ? String(res.data.html_url) : null };
1169
+ }
1140
1170
  async function getRepos(oktoKit) {
1141
1171
  const res = await oktoKit.request("GET /user/repos?sort=updated", {
1142
1172
  headers: {
@@ -1285,13 +1315,83 @@ async function getGithubBlameRanges({ ref, gitHubUrl, path: path8 }, options) {
1285
1315
  login: range.commit.author.user.login
1286
1316
  }));
1287
1317
  }
1318
+ async function createPr({
1319
+ sourceRepoUrl,
1320
+ sourceFilePath,
1321
+ targetFilePath,
1322
+ userRepoUrl,
1323
+ title
1324
+ }, options) {
1325
+ const oktoKit = getOktoKit(options);
1326
+ const { owner: sourceOwner, repo: sourceRepo } = parseOwnerAndRepo(sourceRepoUrl);
1327
+ const { owner, repo } = parseOwnerAndRepo(userRepoUrl);
1328
+ const sourceFileContentResponse = await oktoKit.rest.repos.getContent({
1329
+ owner: sourceOwner,
1330
+ repo: sourceRepo,
1331
+ path: "/" + sourceFilePath
1332
+ });
1333
+ const newBranchName = `mobb/workflow-${Date.now()}`;
1334
+ oktoKit.rest.git.createRef({
1335
+ owner,
1336
+ repo,
1337
+ ref: `refs/heads/${newBranchName}`,
1338
+ sha: await oktoKit.rest.git.getRef({ owner, repo, ref: "heads/main" }).then((response) => response.data.object.sha)
1339
+ });
1340
+ const decodedContent = Buffer.from(
1341
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1342
+ // @ts-ignore
1343
+ sourceFileContentResponse.data.content,
1344
+ "base64"
1345
+ ).toString("utf-8");
1346
+ const createTreeResponse = await oktoKit.rest.git.createTree({
1347
+ owner,
1348
+ repo,
1349
+ base_tree: await oktoKit.rest.git.getRef({ owner, repo, ref: `heads/main` }).then((response) => response.data.object.sha),
1350
+ tree: [
1351
+ {
1352
+ path: targetFilePath,
1353
+ mode: "100644",
1354
+ type: "blob",
1355
+ content: decodedContent
1356
+ }
1357
+ ]
1358
+ });
1359
+ const createCommitResponse = await oktoKit.rest.git.createCommit({
1360
+ owner,
1361
+ repo,
1362
+ message: "Add new yaml file",
1363
+ tree: createTreeResponse.data.sha,
1364
+ parents: [
1365
+ await oktoKit.rest.git.getRef({ owner, repo, ref: `heads/main` }).then((response) => response.data.object.sha)
1366
+ ]
1367
+ });
1368
+ await oktoKit.rest.git.updateRef({
1369
+ owner,
1370
+ repo,
1371
+ ref: `heads/${newBranchName}`,
1372
+ sha: createCommitResponse.data.sha
1373
+ });
1374
+ const createPRResponse = await oktoKit.rest.pulls.create({
1375
+ owner,
1376
+ repo,
1377
+ title,
1378
+ head: newBranchName,
1379
+ base: "main"
1380
+ });
1381
+ return {
1382
+ pull_request_url: createPRResponse.data.html_url
1383
+ };
1384
+ }
1288
1385
 
1289
1386
  // src/features/analysis/scm/github/consts.ts
1290
1387
  var POST_COMMENT_PATH = "POST /repos/{owner}/{repo}/pulls/{pull_number}/comments";
1291
1388
  var DELETE_COMMENT_PATH = "DELETE /repos/{owner}/{repo}/pulls/comments/{comment_id}";
1292
1389
  var UPDATE_COMMENT_PATH = "PATCH /repos/{owner}/{repo}/pulls/comments/{comment_id}";
1293
- var GET_PR_COMMENTS_PATH = "GET /repos/{owner}/{repo}/pulls/comments";
1390
+ var GET_PR_COMMENTS_PATH = "GET /repos/{owner}/{repo}/pulls/{pull_number}/comments";
1391
+ var GET_PR_COMMENT_PATH = "GET /repos/{owner}/{repo}/pulls/comments/{comment_id}";
1294
1392
  var GET_PR = "GET /repos/{owner}/{repo}/pulls/{pull_number}";
1393
+ var CREATE_OR_UPDATE_A_REPOSITORY_SECRET = "PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}";
1394
+ var GET_A_REPOSITORY_PUBLIC_KEY = "GET /repos/{owner}/{repo}/actions/secrets/public-key";
1295
1395
 
1296
1396
  // src/features/analysis/scm/github/github-v2.ts
1297
1397
  function postPrComment(client, params) {
@@ -1303,32 +1403,32 @@ function updatePrComment(client, params) {
1303
1403
  function getPrComments(client, params) {
1304
1404
  return client.request(GET_PR_COMMENTS_PATH, params);
1305
1405
  }
1406
+ function getPrComment(client, params) {
1407
+ return client.request(GET_PR_COMMENT_PATH, params);
1408
+ }
1306
1409
  function deleteComment(client, params) {
1307
1410
  return client.request(DELETE_COMMENT_PATH, params);
1308
1411
  }
1309
- function getPr(client, params) {
1310
- return client.request(GET_PR, params);
1412
+ function getPrDiff(client, params) {
1413
+ return client.request(GET_PR, { ...params, mediaType: { format: "diff" } });
1414
+ }
1415
+ function createOrUpdateRepositorySecret(client, params) {
1416
+ return client.request(CREATE_OR_UPDATE_A_REPOSITORY_SECRET, params);
1417
+ }
1418
+ function getARepositoryPublicKey(client, params) {
1419
+ return client.request(GET_A_REPOSITORY_PUBLIC_KEY, params);
1311
1420
  }
1312
1421
 
1313
- // src/features/analysis/scm/scmSubmit.ts
1422
+ // src/features/analysis/scm/scmSubmit/index.ts
1314
1423
  import fs from "node:fs/promises";
1315
1424
  import os from "os";
1316
1425
  import path3 from "path";
1317
1426
  import { simpleGit as simpleGit2 } from "simple-git";
1318
1427
  import tmp from "tmp";
1428
+ import { z as z5 } from "zod";
1429
+
1430
+ // src/features/analysis/scm/scmSubmit/types.ts
1319
1431
  import { z as z4 } from "zod";
1320
- var isValidBranchName = async (branchName) => {
1321
- const git = simpleGit2();
1322
- try {
1323
- const res = await git.raw(["check-ref-format", "--branch", branchName]);
1324
- if (res) {
1325
- return true;
1326
- }
1327
- return false;
1328
- } catch (e) {
1329
- return false;
1330
- }
1331
- };
1332
1432
  var BaseSubmitToScmMessageZ = z4.object({
1333
1433
  submitFixRequestId: z4.string().uuid(),
1334
1434
  fixes: z4.array(
@@ -1349,7 +1449,8 @@ var CommitToSameBranchParamsZ = BaseSubmitToScmMessageZ.merge(
1349
1449
  type: z4.literal(submitToScmMessageType.commitToSameBranch),
1350
1450
  branch: z4.string(),
1351
1451
  commitMessage: z4.string(),
1352
- commitDescription: z4.string().nullish()
1452
+ commitDescription: z4.string().nullish(),
1453
+ githubCommentId: z4.number().nullish()
1353
1454
  })
1354
1455
  );
1355
1456
  var SubmitFixesToDifferentBranchParamsZ = z4.object({
@@ -1366,8 +1467,7 @@ var FixResponseArrayZ = z4.array(
1366
1467
  fixId: z4.string().uuid()
1367
1468
  })
1368
1469
  );
1369
- var SubmitFixesResponseMessageZ = z4.object({
1370
- type: z4.nativeEnum(submitToScmMessageType),
1470
+ var SubmitFixesBaseResponseMessageZ = z4.object({
1371
1471
  submitFixRequestId: z4.string().uuid(),
1372
1472
  submitBranches: z4.array(
1373
1473
  z4.object({
@@ -1387,7 +1487,33 @@ var SubmitFixesResponseMessageZ = z4.object({
1387
1487
  })
1388
1488
  }).optional()
1389
1489
  });
1390
- var FixesZ = z4.array(z4.object({ fixId: z4.string(), diff: z4.string() })).nonempty();
1490
+ var SubmitFixesToSameBranchResponseMessageZ = z4.object({
1491
+ type: z4.literal(submitToScmMessageType.commitToSameBranch),
1492
+ githubCommentId: z4.number().nullish()
1493
+ }).merge(SubmitFixesBaseResponseMessageZ);
1494
+ var SubmitFixesToDifferentBranchResponseMessageZ = z4.object({
1495
+ type: z4.literal(submitToScmMessageType.submitFixesForDifferentBranch),
1496
+ githubCommentId: z4.number().optional()
1497
+ }).merge(SubmitFixesBaseResponseMessageZ);
1498
+ var SubmitFixeResponseMessageZ = z4.discriminatedUnion("type", [
1499
+ SubmitFixesToSameBranchResponseMessageZ,
1500
+ SubmitFixesToDifferentBranchResponseMessageZ
1501
+ ]);
1502
+
1503
+ // src/features/analysis/scm/scmSubmit/index.ts
1504
+ var isValidBranchName = async (branchName) => {
1505
+ const git = simpleGit2();
1506
+ try {
1507
+ const res = await git.raw(["check-ref-format", "--branch", branchName]);
1508
+ if (res) {
1509
+ return true;
1510
+ }
1511
+ return false;
1512
+ } catch (e) {
1513
+ return false;
1514
+ }
1515
+ };
1516
+ var FixesZ = z5.array(z5.object({ fixId: z5.string(), diff: z5.string() })).nonempty();
1391
1517
 
1392
1518
  // src/features/analysis/scm/scm.ts
1393
1519
  function getScmLibTypeFromUrl(url) {
@@ -1538,6 +1664,23 @@ var GitlabSCMLib = class extends SCMLib {
1538
1664
  accessToken: this.accessToken
1539
1665
  });
1540
1666
  }
1667
+ async forkRepo() {
1668
+ if (!this.accessToken) {
1669
+ console.error("no access token");
1670
+ throw new Error("no access token");
1671
+ }
1672
+ throw new Error("not supported yet");
1673
+ }
1674
+ async createOrUpdateRepositorySecret() {
1675
+ if (!this.accessToken) {
1676
+ console.error("no access token");
1677
+ throw new Error("no access token");
1678
+ }
1679
+ throw new Error("not supported yet");
1680
+ }
1681
+ async createPullRequestWithNewFile(_sourceRepoUrl, _sourceFilePath, _targetFilePath, _userRepoUrl, _title) {
1682
+ throw new Error("not implemented");
1683
+ }
1541
1684
  async getRepoList() {
1542
1685
  if (!this.accessToken) {
1543
1686
  console.error("no access token");
@@ -1659,8 +1802,15 @@ var GitlabSCMLib = class extends SCMLib {
1659
1802
  gitlabAuthToken: this.accessToken
1660
1803
  });
1661
1804
  }
1805
+ getPrComment(_commentId) {
1806
+ throw new Error("getPrComment not implemented.");
1807
+ }
1808
+ updatePrComment(_params, _oktokit) {
1809
+ throw new Error("updatePrComment not implemented.");
1810
+ }
1662
1811
  };
1663
1812
  var GithubSCMLib = class extends SCMLib {
1813
+ // we don't always need a url, what's important is that we have an access token
1664
1814
  constructor(url, accessToken) {
1665
1815
  super(url, accessToken);
1666
1816
  __publicField(this, "oktokit");
@@ -1682,6 +1832,54 @@ var GithubSCMLib = class extends SCMLib {
1682
1832
  })
1683
1833
  );
1684
1834
  }
1835
+ async forkRepo(repoUrl) {
1836
+ if (!this.accessToken) {
1837
+ console.error("no access token");
1838
+ throw new Error("no access token");
1839
+ }
1840
+ return forkRepo({
1841
+ repoUrl,
1842
+ accessToken: this.accessToken
1843
+ });
1844
+ }
1845
+ async createOrUpdateRepositorySecret(params, _oktokit) {
1846
+ if (!_oktokit && !this.accessToken || !this.url) {
1847
+ throw new Error("cannot delete comment without access token or url");
1848
+ }
1849
+ const oktokit = _oktokit || this.oktokit;
1850
+ const { owner, repo } = parseOwnerAndRepo(this.url);
1851
+ const { data: repositoryPublicKeyResponse } = await getARepositoryPublicKey(
1852
+ oktokit,
1853
+ {
1854
+ owner,
1855
+ repo
1856
+ }
1857
+ );
1858
+ const { key_id, key } = repositoryPublicKeyResponse;
1859
+ const encryptedValue = await encryptSecret(params.value, key);
1860
+ return createOrUpdateRepositorySecret(oktokit, {
1861
+ encrypted_value: encryptedValue,
1862
+ secret_name: params.name,
1863
+ key_id,
1864
+ owner,
1865
+ repo
1866
+ });
1867
+ }
1868
+ async createPullRequestWithNewFile(sourceRepoUrl, sourceFilePath, targetFilePath, userRepoUrl, title) {
1869
+ const { pull_request_url } = await createPr(
1870
+ {
1871
+ sourceRepoUrl,
1872
+ sourceFilePath,
1873
+ targetFilePath,
1874
+ userRepoUrl,
1875
+ title
1876
+ },
1877
+ {
1878
+ githubAuthToken: this.accessToken
1879
+ }
1880
+ );
1881
+ return { pull_request_url };
1882
+ }
1685
1883
  async validateParams() {
1686
1884
  return githubValidateParams(this.url, this.accessToken);
1687
1885
  }
@@ -1739,13 +1937,12 @@ var GithubSCMLib = class extends SCMLib {
1739
1937
  throw new Error("cannot get Pr Comments without access token or url");
1740
1938
  }
1741
1939
  const { owner, repo } = parseOwnerAndRepo(this.url);
1742
- const prRes = await getPr(this.oktokit, {
1940
+ const prRes = await getPrDiff(this.oktokit, {
1743
1941
  ...params,
1744
1942
  owner,
1745
1943
  repo
1746
1944
  });
1747
- const diffUrl = prRes.data.diff_url;
1748
- return this.oktokit.request("GET " + diffUrl);
1945
+ return z6.string().parse(prRes.data);
1749
1946
  }
1750
1947
  async getRepoList() {
1751
1948
  if (!this.accessToken) {
@@ -1843,6 +2040,18 @@ var GithubSCMLib = class extends SCMLib {
1843
2040
  }
1844
2041
  );
1845
2042
  }
2043
+ async getPrComment(commentId) {
2044
+ if (!this.url) {
2045
+ console.error("no url");
2046
+ throw new Error("no url");
2047
+ }
2048
+ const { owner, repo } = parseOwnerAndRepo(this.url);
2049
+ return await getPrComment(this.oktokit, {
2050
+ repo,
2051
+ owner,
2052
+ comment_id: commentId
2053
+ });
2054
+ }
1846
2055
  async getRepoDefaultBranch() {
1847
2056
  if (!this.url) {
1848
2057
  console.error("no url");
@@ -1878,6 +2087,18 @@ var StubSCMLib = class extends SCMLib {
1878
2087
  console.error("validateParams() not implemented");
1879
2088
  throw new Error("validateParams() not implemented");
1880
2089
  }
2090
+ async forkRepo() {
2091
+ console.error("forkRepo() not implemented");
2092
+ throw new Error("forkRepo() not implemented");
2093
+ }
2094
+ async createOrUpdateRepositorySecret() {
2095
+ console.error("forkRepo() not implemented");
2096
+ throw new Error("forkRepo() not implemented");
2097
+ }
2098
+ async createPullRequestWithNewFile(_sourceRepoUrl, _sourceFilePath, _targetFilePath, _userRepoUrl, _title) {
2099
+ console.error("createPullRequestWithNewFile() not implemented");
2100
+ throw new Error("createPullRequestWithNewFile() not implemented");
2101
+ }
1881
2102
  async getRepoList() {
1882
2103
  console.error("getBranchList() not implemented");
1883
2104
  throw new Error("getBranchList() not implemented");
@@ -1910,14 +2131,22 @@ var StubSCMLib = class extends SCMLib {
1910
2131
  console.error("getRepoDefaultBranch() not implemented");
1911
2132
  throw new Error("getRepoDefaultBranch() not implemented");
1912
2133
  }
2134
+ async getPrComment(_commentId) {
2135
+ console.error("getPrComment() not implemented");
2136
+ throw new Error("getPrComment() not implemented");
2137
+ }
2138
+ async updatePrComment() {
2139
+ console.error("updatePrComment() not implemented");
2140
+ throw new Error("updatePrComment() not implemented");
2141
+ }
1913
2142
  };
1914
2143
 
1915
2144
  // src/features/analysis/scm/gitlab.ts
1916
2145
  function removeTrailingSlash2(str) {
1917
2146
  return str.trim().replace(/\/+$/, "");
1918
2147
  }
1919
- var EnvVariablesZod2 = z5.object({
1920
- GITLAB_API_TOKEN: z5.string().optional()
2148
+ var EnvVariablesZod2 = z7.object({
2149
+ GITLAB_API_TOKEN: z7.string().optional()
1921
2150
  });
1922
2151
  var { GITLAB_API_TOKEN } = EnvVariablesZod2.parse(process.env);
1923
2152
  function getGitBeaker(options) {
@@ -2146,38 +2375,13 @@ async function getGitlabBlameRanges({ ref, gitlabUrl, path: path8 }, options) {
2146
2375
  };
2147
2376
  });
2148
2377
  }
2149
- var GitlabAuthResultZ = z5.object({
2150
- access_token: z5.string(),
2151
- token_type: z5.string(),
2152
- refresh_token: z5.string()
2378
+ var GitlabAuthResultZ = z7.object({
2379
+ access_token: z7.string(),
2380
+ token_type: z7.string(),
2381
+ refresh_token: z7.string()
2153
2382
  });
2154
2383
 
2155
- // src/features/analysis/utils/calculate_ranges.ts
2156
- function calculateRanges(integers) {
2157
- if (integers.length === 0) {
2158
- return [];
2159
- }
2160
- integers.sort((a, b) => a - b);
2161
- const ranges = integers.reduce(
2162
- (result, current, index) => {
2163
- if (index === 0) {
2164
- return [...result, [current, current]];
2165
- }
2166
- const currentRange = result[result.length - 1];
2167
- const [_start, end] = currentRange;
2168
- if (current === end + 1) {
2169
- currentRange[1] = current;
2170
- } else {
2171
- result.push([current, current]);
2172
- }
2173
- return result;
2174
- },
2175
- []
2176
- );
2177
- return ranges;
2178
- }
2179
-
2180
- // src/features/analysis/utils/get_issue_type.ts
2384
+ // src/features/analysis/scm/utils/get_issue_type.ts
2181
2385
  var getIssueType = (issueType) => {
2182
2386
  switch (issueType) {
2183
2387
  case "SQL_Injection" /* SqlInjection */:
@@ -2236,48 +2440,86 @@ var getIssueType = (issueType) => {
2236
2440
  }
2237
2441
  };
2238
2442
 
2239
- // src/features/analysis/utils/index.ts
2240
- function getFixUrlWithRedirect({
2241
- fixId,
2242
- projectId,
2243
- organizationId,
2244
- analysisId,
2245
- redirectUrl
2246
- }) {
2443
+ // src/features/analysis/scm/utils/index.ts
2444
+ function getFixUrlWithRedirect(params) {
2445
+ const {
2446
+ fixId,
2447
+ projectId,
2448
+ organizationId,
2449
+ analysisId,
2450
+ redirectUrl,
2451
+ appBaseUrl,
2452
+ commentId
2453
+ } = params;
2454
+ const searchParams = new URLSearchParams();
2455
+ searchParams.append("commit_redirect_url", redirectUrl);
2456
+ searchParams.append("comment_id", commentId.toString());
2247
2457
  return `${getFixUrl({
2458
+ appBaseUrl,
2248
2459
  fixId,
2249
2460
  projectId,
2250
2461
  organizationId,
2251
2462
  analysisId
2252
- })}?commit_redirect_url=${encodeURIComponent(redirectUrl)}`;
2463
+ })}?${searchParams.toString()}`;
2253
2464
  }
2254
2465
  function getFixUrl({
2466
+ appBaseUrl,
2255
2467
  fixId,
2256
2468
  projectId,
2257
2469
  organizationId,
2258
2470
  analysisId
2259
2471
  }) {
2260
- return `${WEB_APP_URL}/organization/${organizationId}/project/${projectId}/report/${analysisId}/fix/${fixId}`;
2472
+ return `${appBaseUrl}/organization/${organizationId}/project/${projectId}/report/${analysisId}/fix/${fixId}`;
2261
2473
  }
2262
- function getCommitUrl({
2263
- fixId,
2264
- projectId,
2265
- organizationId,
2266
- analysisId,
2267
- redirectUrl
2268
- }) {
2474
+ function getCommitUrl(params) {
2475
+ const {
2476
+ fixId,
2477
+ projectId,
2478
+ organizationId,
2479
+ analysisId,
2480
+ redirectUrl,
2481
+ appBaseUrl,
2482
+ commentId
2483
+ } = params;
2484
+ const searchParams = new URLSearchParams();
2485
+ searchParams.append("redirect_url", redirectUrl);
2486
+ searchParams.append("comment_id", commentId.toString());
2269
2487
  return `${getFixUrl({
2488
+ appBaseUrl,
2270
2489
  fixId,
2271
2490
  projectId,
2272
2491
  organizationId,
2273
2492
  analysisId
2274
- })}/commit?redirect_url=${encodeURIComponent(redirectUrl)}`;
2493
+ })}/commit?${searchParams.toString()}`;
2494
+ }
2495
+
2496
+ // src/features/analysis/utils/calculate_ranges.ts
2497
+ function calculateRanges(integers) {
2498
+ if (integers.length === 0) {
2499
+ return [];
2500
+ }
2501
+ integers.sort((a, b) => a - b);
2502
+ const ranges = integers.reduce(
2503
+ (result, current, index) => {
2504
+ if (index === 0) {
2505
+ return [...result, [current, current]];
2506
+ }
2507
+ const currentRange = result[result.length - 1];
2508
+ const [_start, end] = currentRange;
2509
+ if (current === end + 1) {
2510
+ currentRange[1] = current;
2511
+ } else {
2512
+ result.push([current, current]);
2513
+ }
2514
+ return result;
2515
+ },
2516
+ []
2517
+ );
2518
+ return ranges;
2275
2519
  }
2276
2520
 
2277
2521
  // src/features/analysis/handle_finished_analysis.ts
2278
2522
  var debug4 = Debug4("mobbdev:handle-finished-analysis");
2279
- var MOBB_ICON_IMG = "![image](https://github.com/yhaggai/GitHub-Fixer-Demo/assets/1255845/30f566df-6544-4612-929e-2ee5e8b9d345)";
2280
- var COMMIT_FIX_SVG = `https://felt-laptop-20190711103614-deployment.s3.us-east-1.amazonaws.com/commit-button.svg`;
2281
2523
  var commitFixButton = (commitUrl) => `<a href="${commitUrl}"><img src=${COMMIT_FIX_SVG}></a>`;
2282
2524
  function scannerToFriendlyString(scanner) {
2283
2525
  switch (scanner) {
@@ -2301,7 +2543,7 @@ async function getFixesFromDiff(params) {
2301
2543
  });
2302
2544
  const lineAddedRanges = calculateRanges(fileNumbers);
2303
2545
  const fileFilter = {
2304
- path: z6.string().parse(file.to),
2546
+ path: z8.string().parse(file.to),
2305
2547
  ranges: lineAddedRanges.map(([startLine, endLine]) => ({
2306
2548
  endLine,
2307
2549
  startLine
@@ -2333,16 +2575,19 @@ async function handleFinishedAnalysis({
2333
2575
  }
2334
2576
  } = getAnalysis.analysis;
2335
2577
  const { commitSha, pullRequest } = getAnalysis.analysis.repo;
2336
- const getPrDiff = await scm.getPrDiff({ pull_number: pullRequest });
2578
+ const diff = await scm.getPrDiff({ pull_number: pullRequest });
2337
2579
  const { vulnerabilityReportIssueCodeNodes } = await getFixesFromDiff({
2338
- diff: getPrDiff.data,
2580
+ diff,
2339
2581
  gqlClient,
2340
2582
  vulnerabilityReportId: getAnalysis.analysis.vulnerabilityReportId
2341
2583
  });
2342
- const comments = await scm.getPrComments({}, githubActionOctokit);
2584
+ const comments = await scm.getPrComments(
2585
+ { pull_number: pullRequest },
2586
+ githubActionOctokit
2587
+ );
2343
2588
  await Promise.all(
2344
2589
  comments.data.filter((comment) => {
2345
- return comment.body.includes("fix by Mobb is ready");
2590
+ return comment.body.includes(MOBB_ICON_IMG);
2346
2591
  }).map((comment) => {
2347
2592
  try {
2348
2593
  return scm.deleteComment(
@@ -2374,25 +2619,30 @@ async function handleFinishedAnalysis({
2374
2619
  },
2375
2620
  githubActionOctokit
2376
2621
  );
2622
+ const commentId = commentRes.data.id;
2377
2623
  const commitUrl = getCommitUrl({
2624
+ appBaseUrl: WEB_APP_URL,
2378
2625
  fixId: fix_by_pk.id,
2379
2626
  projectId,
2380
2627
  analysisId,
2381
2628
  organizationId,
2382
- redirectUrl: commentRes.data.html_url
2629
+ redirectUrl: commentRes.data.html_url,
2630
+ commentId
2383
2631
  });
2384
2632
  const fixUrl = getFixUrlWithRedirect({
2633
+ appBaseUrl: WEB_APP_URL,
2385
2634
  fixId: fix_by_pk.id,
2386
2635
  projectId,
2387
2636
  analysisId,
2388
2637
  organizationId,
2389
- redirectUrl: commentRes.data.html_url
2638
+ redirectUrl: commentRes.data.html_url,
2639
+ commentId
2390
2640
  });
2391
2641
  const scanerString = scannerToFriendlyString(scanner);
2392
2642
  const issueType = getIssueType(fix_by_pk.issueType);
2393
- const title = `# ${MOBB_ICON_IMG} ${issueType} fix by Mobb is ready`;
2643
+ const title = `# ![image](${MOBB_ICON_IMG}) ${issueType} fix by Mobb is ready`;
2394
2644
  const subTitle = `### Apply the following code change to fix ${issueType} issue detected by ${scanerString}:`;
2395
- const diff = `\`\`\`diff
2645
+ const diff2 = `\`\`\`diff
2396
2646
  ${patch}
2397
2647
  \`\`\``;
2398
2648
  const fixPageLink = `[Learn more and fine tune the fix](${fixUrl})`;
@@ -2400,12 +2650,12 @@ ${patch}
2400
2650
  {
2401
2651
  body: `${title}
2402
2652
  ${subTitle}
2403
- ${diff}
2653
+ ${diff2}
2404
2654
  ${commitFixButton(
2405
2655
  commitUrl
2406
2656
  )}
2407
2657
  ${fixPageLink}`,
2408
- comment_id: commentRes.data.id
2658
+ comment_id: commentId
2409
2659
  },
2410
2660
  githubActionOctokit
2411
2661
  );
@@ -2892,6 +3142,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
2892
3142
  srcPath,
2893
3143
  commitHash,
2894
3144
  ref,
3145
+ experimentalEnabled,
2895
3146
  scanner,
2896
3147
  cxProjectName,
2897
3148
  mobbProjectName,
@@ -2993,7 +3244,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
2993
3244
  gqlClient,
2994
3245
  scm,
2995
3246
  githubActionOctokit: new Octokit3({ auth: githubActionToken }),
2996
- scanner: z7.nativeEnum(SCANNERS).parse(scanner)
3247
+ scanner: z9.nativeEnum(SCANNERS).parse(scanner)
2997
3248
  })
2998
3249
  );
2999
3250
  }
@@ -3005,11 +3256,12 @@ async function _scan(params, { skipPrompts = false } = {}) {
3005
3256
  try {
3006
3257
  const sumbitRes = await gqlClient.submitVulnerabilityReport({
3007
3258
  fixReportId: reportUploadInfo.fixReportId,
3008
- repoUrl: z7.string().parse(repo),
3259
+ repoUrl: z9.string().parse(repo),
3009
3260
  reference,
3010
3261
  projectId,
3011
3262
  vulnerabilityReportFileName: "report.json",
3012
3263
  sha,
3264
+ experimentalEnabled,
3013
3265
  pullRequest: params.pullRequest
3014
3266
  });
3015
3267
  if (sumbitRes.submitVulnerabilityReport.__typename !== "VulnerabilityReport") {
@@ -3255,6 +3507,7 @@ async function review(params, { skipPrompts = true } = {}) {
3255
3507
  apiKey,
3256
3508
  ci: true,
3257
3509
  commitHash,
3510
+ experimentalEnabled: false,
3258
3511
  mobbProjectName,
3259
3512
  pullRequest,
3260
3513
  githubToken,
@@ -3370,7 +3623,7 @@ var commitHashOption = {
3370
3623
  // src/args/validation.ts
3371
3624
  import chalk6 from "chalk";
3372
3625
  import path7 from "path";
3373
- import { z as z8 } from "zod";
3626
+ import { z as z10 } from "zod";
3374
3627
  function throwRepoUrlErrorMessage({
3375
3628
  error,
3376
3629
  repoUrl,
@@ -3387,7 +3640,7 @@ Example:
3387
3640
  )}`;
3388
3641
  throw new CliError(formattedErrorMessage);
3389
3642
  }
3390
- var UrlZ = z8.string({
3643
+ var UrlZ = z10.string({
3391
3644
  invalid_type_error: "is not a valid GitHub / GitLab URL"
3392
3645
  }).refine((data) => !!parseScmURL(data), {
3393
3646
  message: "is not a valid GitHub / GitLab URL"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "0.0.67",
3
+ "version": "0.0.69",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "https://github.com/mobb-dev/bugsy",
6
6
  "main": "dist/index.js",
@@ -27,6 +27,7 @@
27
27
  "@octokit/graphql": "5.0.5",
28
28
  "@octokit/plugin-rest-endpoint-methods": "7.0.1",
29
29
  "@octokit/request-error": "3.0.3",
30
+ "@types/libsodium-wrappers": "0.7.13",
30
31
  "adm-zip": "0.5.10",
31
32
  "axios": "1.5.0",
32
33
  "chalk": "5.3.0",
@@ -42,6 +43,7 @@
42
43
  "inquirer": "9.2.7",
43
44
  "isomorphic-ws": "5.0.0",
44
45
  "istextorbinary": "6.0.0",
46
+ "libsodium-wrappers": "0.7.13",
45
47
  "nanospinner": "1.1.0",
46
48
  "node-fetch": "3.3.1",
47
49
  "octokit": "2.0.14",