mobbdev 0.0.130 → 0.0.132

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 +938 -896
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -520,456 +520,21 @@ var CliError = class extends Error {
520
520
  // src/features/analysis/index.ts
521
521
  import chalk4 from "chalk";
522
522
  import Configstore from "configstore";
523
- import Debug11 from "debug";
524
- import extract from "extract-zip";
525
- import fetch3 from "node-fetch";
526
- import open2 from "open";
527
- import semver from "semver";
528
- import tmp2 from "tmp";
529
- import { z as z12 } from "zod";
530
-
531
- // src/features/analysis/git.ts
532
- import Debug2 from "debug";
533
- import { simpleGit } from "simple-git";
534
- var debug2 = Debug2("mobbdev:git");
535
- var GIT_NOT_INITIALIZED_ERROR_MESSAGE = "not a git repository";
536
- async function getGitInfo(srcDirPath) {
537
- debug2("getting git info for %s", srcDirPath);
538
- const git = simpleGit({
539
- baseDir: srcDirPath,
540
- maxConcurrentProcesses: 1,
541
- trimmed: true
542
- });
543
- let repoUrl = "";
544
- let hash = "";
545
- let reference = "";
546
- try {
547
- repoUrl = (await git.getConfig("remote.origin.url")).value || "";
548
- hash = await git.revparse(["HEAD"]) || "";
549
- reference = await git.revparse(["--abbrev-ref", "HEAD"]) || "";
550
- } catch (e) {
551
- if (e instanceof Error) {
552
- debug2("failed to run git %o", e);
553
- if (e.message.includes(" spawn ")) {
554
- debug2("git cli not installed");
555
- } else if (e.message.includes(GIT_NOT_INITIALIZED_ERROR_MESSAGE)) {
556
- debug2("folder is not a git repo");
557
- return {
558
- success: false,
559
- hash: void 0,
560
- reference: void 0,
561
- repoUrl: void 0
562
- };
563
- } else {
564
- throw e;
565
- }
566
- }
567
- throw e;
568
- }
569
- if (repoUrl.endsWith(".git")) {
570
- repoUrl = repoUrl.slice(0, -".git".length);
571
- }
572
- if (repoUrl.startsWith("git@github.com:")) {
573
- repoUrl = repoUrl.replace("git@github.com:", "https://github.com/");
574
- }
575
- return {
576
- success: true,
577
- repoUrl,
578
- hash,
579
- reference
580
- };
581
- }
582
-
583
- // src/features/analysis/graphql/gql.ts
584
- import Debug3 from "debug";
585
- import { GraphQLClient } from "graphql-request";
586
- import { v4 as uuidv4 } from "uuid";
587
-
588
- // src/features/analysis/graphql/subscribe.ts
589
- import { createClient } from "graphql-ws";
590
- import WebSocket from "ws";
591
- var SUBSCRIPTION_TIMEOUT_MS = 10 * 60 * 1e3;
592
- function createWSClient(options) {
593
- return createClient({
594
- url: options.url,
595
- webSocketImpl: options.websocket || WebSocket,
596
- connectionParams: () => {
597
- return {
598
- headers: options.type === "apiKey" ? {
599
- [API_KEY_HEADER_NAME]: options.apiKey
600
- } : { authorization: `Bearer ${options.token}` }
601
- };
602
- }
603
- });
604
- }
605
- function subscribe(query, variables, callback, wsClientOptions) {
606
- return new Promise((resolve, reject) => {
607
- let timer = null;
608
- const { timeoutInMs = SUBSCRIPTION_TIMEOUT_MS } = wsClientOptions;
609
- const client = createWSClient({
610
- ...wsClientOptions,
611
- websocket: WebSocket,
612
- url: API_URL.replace("http", "ws")
613
- });
614
- const unsubscribe = client.subscribe(
615
- { query, variables },
616
- {
617
- next: (data) => {
618
- function callbackResolve(data2) {
619
- unsubscribe();
620
- if (timer) {
621
- clearTimeout(timer);
622
- }
623
- resolve(data2);
624
- }
625
- function callbackReject(data2) {
626
- unsubscribe();
627
- if (timer) {
628
- clearTimeout(timer);
629
- }
630
- reject(data2);
631
- }
632
- if (!data.data) {
633
- reject(
634
- new Error(
635
- `Broken data object from graphQL subscribe: ${JSON.stringify(
636
- data
637
- )} for query: ${query}`
638
- )
639
- );
640
- } else {
641
- callback(callbackResolve, callbackReject, data.data);
642
- }
643
- },
644
- error: (error) => {
645
- if (timer) {
646
- clearTimeout(timer);
647
- }
648
- reject(error);
649
- },
650
- complete: () => {
651
- return;
652
- }
653
- }
654
- );
655
- if (typeof timeoutInMs === "number") {
656
- timer = setTimeout(() => {
657
- unsubscribe();
658
- reject(
659
- new Error(
660
- `Timeout expired for graphQL subscribe query: ${query} with timeout: ${timeoutInMs}`
661
- )
662
- );
663
- }, timeoutInMs);
664
- }
665
- });
666
- }
667
-
668
- // src/features/analysis/graphql/types.ts
669
- import { z as z2 } from "zod";
670
- var VulnerabilityReportIssueCodeNodeZ = z2.object({
671
- vulnerabilityReportIssueId: z2.string(),
672
- path: z2.string(),
673
- startLine: z2.number(),
674
- vulnerabilityReportIssue: z2.object({
675
- fixId: z2.string()
676
- })
677
- });
678
- var GetVulByNodesMetadataZ = z2.object({
679
- vulnerabilityReportIssueCodeNodes: z2.array(VulnerabilityReportIssueCodeNodeZ),
680
- nonFixablePrVuls: z2.object({
681
- aggregate: z2.object({
682
- count: z2.number()
683
- })
684
- }),
685
- fixablePrVuls: z2.object({
686
- aggregate: z2.object({
687
- count: z2.number()
688
- })
689
- }),
690
- totalScanVulnerabilities: z2.object({
691
- aggregate: z2.object({
692
- count: z2.number()
693
- })
694
- })
695
- });
696
-
697
- // src/features/analysis/graphql/gql.ts
698
- var debug3 = Debug3("mobbdev:gql");
699
- var API_KEY_HEADER_NAME = "x-mobb-key";
700
- var REPORT_STATE_CHECK_DELAY = 5 * 1e3;
701
- var GQLClient = class {
702
- constructor(args) {
703
- __publicField(this, "_client");
704
- __publicField(this, "_clientSdk");
705
- __publicField(this, "_auth");
706
- debug3(`init with ${args}`);
707
- this._auth = args;
708
- this._client = new GraphQLClient(API_URL, {
709
- headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
710
- Authorization: `Bearer ${args.token}`
711
- },
712
- requestMiddleware: (request) => {
713
- const requestId = uuidv4();
714
- debug3(
715
- `sending API request with id: ${requestId} and with request: ${request.body}`
716
- );
717
- return {
718
- ...request,
719
- headers: {
720
- ...request.headers,
721
- "x-hasura-request-id": requestId
722
- }
723
- };
724
- }
725
- });
726
- this._clientSdk = getSdk(this._client);
727
- }
728
- async getUserInfo() {
729
- const { me } = await this._clientSdk.Me();
730
- return me;
731
- }
732
- async createCliLogin(variables) {
733
- const res = await this._clientSdk.CreateCliLogin(variables, {
734
- // We may have outdated API key in the config storage. Avoid using it for the login request.
735
- [API_KEY_HEADER_NAME]: ""
736
- });
737
- return res.insert_cli_login_one?.id || "";
738
- }
739
- async verifyToken() {
740
- await this.createCommunityUser();
741
- try {
742
- await this.getUserInfo();
743
- } catch (e) {
744
- debug3("verify token failed %o", e);
745
- return false;
746
- }
747
- return true;
748
- }
749
- async getOrgAndProjectId(projectName) {
750
- const getOrgAndProjectIdResult = await this._clientSdk.getOrgAndProjectId();
751
- const org = getOrgAndProjectIdResult?.users?.at(0)?.userOrganizationsAndUserOrganizationRoles?.at(0)?.organization;
752
- if (!org?.id) {
753
- throw new Error("Organization not found");
754
- }
755
- const project = projectName ? org?.projects.find((project2) => project2.name === projectName) ?? null : org?.projects[0];
756
- if (!project?.id) {
757
- throw new Error("Project not found");
758
- }
759
- let projectId = project?.id;
760
- if (!projectId) {
761
- const createdProject = await this._clientSdk.CreateProject({
762
- organizationId: org.id,
763
- projectName: projectName || "My project"
764
- });
765
- projectId = createdProject.createProject.projectId;
766
- }
767
- return {
768
- organizationId: org.id,
769
- projectId
770
- };
771
- }
772
- async getEncryptedApiToken(variables) {
773
- const res = await this._clientSdk.GetEncryptedApiToken(variables, {
774
- // We may have outdated API key in the config storage. Avoid using it for the login request.
775
- [API_KEY_HEADER_NAME]: ""
776
- });
777
- return res?.cli_login_by_pk?.encryptedApiToken || null;
778
- }
779
- async createCommunityUser() {
780
- try {
781
- await this._clientSdk.CreateCommunityUser();
782
- } catch (e) {
783
- debug3("create community user failed %o", e);
784
- }
785
- }
786
- async updateScmToken(args) {
787
- const { scmType, url, token, org, username, refreshToken } = args;
788
- const updateScmTokenResult = await this._clientSdk.updateScmToken({
789
- scmType,
790
- url,
791
- token,
792
- org,
793
- username,
794
- refreshToken
795
- });
796
- return updateScmTokenResult;
797
- }
798
- async uploadS3BucketInfo() {
799
- const uploadS3BucketInfoResult = await this._clientSdk.uploadS3BucketInfo({
800
- fileName: "report.json"
801
- });
802
- return uploadS3BucketInfoResult;
803
- }
804
- async getVulByNodesMetadata({
805
- hunks,
806
- vulnerabilityReportId
807
- }) {
808
- const filters = hunks.map((hunk) => {
809
- const filter = {
810
- path: { _eq: hunk.path },
811
- _or: hunk.ranges.flatMap(({ endLine, startLine }) => {
812
- return [
813
- { startLine: { _gte: startLine, _lte: endLine } },
814
- { endLine: { _gte: startLine, _lte: endLine } }
815
- ];
816
- })
817
- };
818
- return filter;
819
- });
820
- const getVulByNodesMetadataRes = await this._clientSdk.getVulByNodesMetadata({
821
- filters: { _or: filters },
822
- vulnerabilityReportId
823
- });
824
- const parsedGetVulByNodesMetadataRes = GetVulByNodesMetadataZ.parse(
825
- getVulByNodesMetadataRes
826
- );
827
- const uniqueVulByNodesMetadata = parsedGetVulByNodesMetadataRes.vulnerabilityReportIssueCodeNodes.reduce((acc, vulnerabilityReportIssueCodeNode) => {
828
- if (acc[vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]) {
829
- return acc;
830
- }
831
- return {
832
- ...acc,
833
- [vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]: vulnerabilityReportIssueCodeNode
834
- };
835
- }, {});
836
- const nonFixablePrVuls = parsedGetVulByNodesMetadataRes.nonFixablePrVuls.aggregate.count;
837
- const fixablePrVuls = parsedGetVulByNodesMetadataRes.fixablePrVuls.aggregate.count;
838
- const totalScanVulnerabilities = parsedGetVulByNodesMetadataRes.totalScanVulnerabilities.aggregate.count;
839
- const vulnerabilitiesOutsidePr = totalScanVulnerabilities - nonFixablePrVuls - fixablePrVuls;
840
- const totalPrVulnerabilities = nonFixablePrVuls + fixablePrVuls;
841
- return {
842
- vulnerabilityReportIssueCodeNodes: Object.values(
843
- uniqueVulByNodesMetadata
844
- ),
845
- nonFixablePrVuls,
846
- fixablePrVuls,
847
- totalScanVulnerabilities,
848
- vulnerabilitiesOutsidePr,
849
- totalPrVulnerabilities
850
- };
851
- }
852
- async digestVulnerabilityReport({
853
- fixReportId,
854
- projectId,
855
- scanSource
856
- }) {
857
- const res = await this._clientSdk.DigestVulnerabilityReport({
858
- fixReportId,
859
- vulnerabilityReportFileName: "report.json",
860
- projectId,
861
- scanSource
862
- });
863
- if (res.digestVulnerabilityReport.__typename !== "VulnerabilityReport") {
864
- throw new Error("Digesting vulnerability report failed");
865
- }
866
- return res.digestVulnerabilityReport;
867
- }
868
- async submitVulnerabilityReport(params) {
869
- const {
870
- fixReportId,
871
- repoUrl,
872
- reference,
873
- projectId,
874
- sha,
875
- experimentalEnabled,
876
- vulnerabilityReportFileName,
877
- pullRequest
878
- } = params;
879
- return await this._clientSdk.SubmitVulnerabilityReport({
880
- fixReportId,
881
- repoUrl,
882
- reference,
883
- vulnerabilityReportFileName,
884
- projectId,
885
- pullRequest,
886
- sha: sha || "",
887
- experimentalEnabled,
888
- scanSource: params.scanSource
889
- });
890
- }
891
- async getFixReportState(fixReportId) {
892
- const res = await this._clientSdk.FixReportState({ id: fixReportId });
893
- return res?.fixReport_by_pk?.state || "Created" /* Created */;
894
- }
895
- async waitFixReportInit(fixReportId, includeDigested = false) {
896
- const FINAL_STATES = [
897
- "Finished" /* Finished */,
898
- "Failed" /* Failed */
899
- ];
900
- let lastState = "Created" /* Created */;
901
- let attempts = 100;
902
- if (includeDigested) {
903
- FINAL_STATES.push("Digested" /* Digested */);
904
- }
905
- do {
906
- await sleep(REPORT_STATE_CHECK_DELAY);
907
- lastState = await this.getFixReportState(fixReportId);
908
- } while (!FINAL_STATES.includes(
909
- lastState
910
- // wait for final the state of the fix report
911
- ) && attempts-- > 0);
912
- return lastState;
913
- }
914
- async getVulnerabilityReportPaths(vulnerabilityReportId) {
915
- const res = await this._clientSdk.GetVulnerabilityReportPaths({
916
- vulnerabilityReportId
917
- });
918
- return res.vulnerability_report_path.map((p) => p.path);
919
- }
920
- async subscribeToAnalysis(params) {
921
- const { callbackStates } = params;
922
- return subscribe(
923
- GetAnalysisDocument,
924
- params.subscribeToAnalysisParams,
925
- async (resolve, reject, data) => {
926
- if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
927
- reject(data);
928
- throw new Error(`Analysis failed with id: ${data.analysis?.id}`);
929
- }
930
- if (callbackStates.includes(data.analysis?.state)) {
931
- await params.callback(data.analysis.id);
932
- resolve(data);
933
- }
934
- },
935
- this._auth.type === "apiKey" ? {
936
- apiKey: this._auth.apiKey,
937
- type: "apiKey",
938
- timeoutInMs: params.timeoutInMs
939
- } : {
940
- token: this._auth.token,
941
- type: "token",
942
- timeoutInMs: params.timeoutInMs
943
- }
944
- );
945
- }
946
- async getAnalysis(analysisId) {
947
- const res = await this._clientSdk.getAnalsyis({
948
- analysisId
949
- });
950
- if (!res.analysis) {
951
- throw new Error(`Analysis not found: ${analysisId}`);
952
- }
953
- return res.analysis;
954
- }
955
- async getFixes(fixIds) {
956
- const res = await this._clientSdk.getFixes({
957
- filters: { id: { _in: fixIds } }
958
- });
959
- return res;
960
- }
961
- };
523
+ import Debug12 from "debug";
524
+ import extract from "extract-zip";
525
+ import fetch3 from "node-fetch";
526
+ import open2 from "open";
527
+ import semver from "semver";
528
+ import tmp2 from "tmp";
529
+ import { z as z12 } from "zod";
962
530
 
963
- // src/features/analysis/handle_finished_analysis.ts
964
- import { Octokit as Octokit3 } from "@octokit/core";
965
- import Debug5 from "debug";
966
- import parseDiff2 from "parse-diff";
967
- import { z as z11 } from "zod";
531
+ // src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
532
+ import Debug4 from "debug";
968
533
 
969
534
  // src/features/analysis/scm/ado.ts
970
535
  import querystring from "node:querystring";
971
536
  import * as api from "azure-devops-node-api";
972
- import { z as z3 } from "zod";
537
+ import { z as z2 } from "zod";
973
538
 
974
539
  // src/features/analysis/scm/types.ts
975
540
  var ReferenceType = /* @__PURE__ */ ((ReferenceType2) => {
@@ -1148,22 +713,22 @@ function removeTrailingSlash(str) {
1148
713
  return str.trim().replace(/\/+$/, "");
1149
714
  }
1150
715
  async function _getOrgsForOauthToken({ oauthToken }) {
1151
- const profileZ = z3.object({
1152
- displayName: z3.string(),
1153
- publicAlias: z3.string().min(1),
1154
- emailAddress: z3.string(),
1155
- coreRevision: z3.number(),
1156
- timeStamp: z3.string(),
1157
- id: z3.string(),
1158
- revision: z3.number()
716
+ const profileZ = z2.object({
717
+ displayName: z2.string(),
718
+ publicAlias: z2.string().min(1),
719
+ emailAddress: z2.string(),
720
+ coreRevision: z2.number(),
721
+ timeStamp: z2.string(),
722
+ id: z2.string(),
723
+ revision: z2.number()
1159
724
  });
1160
- const accountsZ = z3.object({
1161
- count: z3.number(),
1162
- value: z3.array(
1163
- z3.object({
1164
- accountId: z3.string(),
1165
- accountUri: z3.string(),
1166
- accountName: z3.string()
725
+ const accountsZ = z2.object({
726
+ count: z2.number(),
727
+ value: z2.array(
728
+ z2.object({
729
+ accountId: z2.string(),
730
+ accountUri: z2.string(),
731
+ accountName: z2.string()
1167
732
  })
1168
733
  )
1169
734
  });
@@ -1594,10 +1159,10 @@ async function getAdoBlameRanges() {
1594
1159
  return [];
1595
1160
  }
1596
1161
  var ADO_ACCESS_TOKEN_URL = "https://app.vssps.visualstudio.com/oauth2/token";
1597
- var AdoAuthResultZ = z3.object({
1598
- access_token: z3.string().min(1),
1599
- token_type: z3.string().min(1),
1600
- refresh_token: z3.string().min(1)
1162
+ var AdoAuthResultZ = z2.object({
1163
+ access_token: z2.string().min(1),
1164
+ token_type: z2.string().min(1),
1165
+ refresh_token: z2.string().min(1)
1601
1166
  });
1602
1167
  async function getAdoToken({
1603
1168
  token,
@@ -1643,11 +1208,11 @@ var AdoSdk = {
1643
1208
  // src/features/analysis/scm/bitbucket/bitbucket.ts
1644
1209
  import querystring3 from "node:querystring";
1645
1210
  import * as bitbucketPkg from "bitbucket";
1646
- import { z as z10 } from "zod";
1211
+ import { z as z9 } from "zod";
1647
1212
 
1648
1213
  // src/features/analysis/scm/scm.ts
1649
1214
  import { Octokit as Octokit2 } from "@octokit/core";
1650
- import { z as z9 } from "zod";
1215
+ import { z as z8 } from "zod";
1651
1216
 
1652
1217
  // src/features/analysis/scm/github/encryptSecret.ts
1653
1218
  import sodium from "libsodium-wrappers";
@@ -1662,7 +1227,7 @@ async function encryptSecret(secret, key) {
1662
1227
  // src/features/analysis/scm/github/github.ts
1663
1228
  import { RequestError } from "@octokit/request-error";
1664
1229
  import { Octokit } from "octokit";
1665
- import { z as z4 } from "zod";
1230
+ import { z as z3 } from "zod";
1666
1231
 
1667
1232
  // src/features/analysis/scm/utils/get_issue_type.ts
1668
1233
  var getIssueType = (issueType) => {
@@ -1866,8 +1431,8 @@ function normalizeUrl(repoUrl) {
1866
1431
  }
1867
1432
 
1868
1433
  // src/features/analysis/scm/github/github.ts
1869
- var EnvVariablesZod = z4.object({
1870
- GITHUB_API_TOKEN: z4.string().optional()
1434
+ var EnvVariablesZod = z3.object({
1435
+ GITHUB_API_TOKEN: z3.string().optional()
1871
1436
  });
1872
1437
  var { GITHUB_API_TOKEN } = EnvVariablesZod.parse(process.env);
1873
1438
  var GetBlameDocument = `
@@ -1909,17 +1474,25 @@ function getOktoKit(options) {
1909
1474
  const token = options?.githubAuthToken ?? GITHUB_API_TOKEN ?? "";
1910
1475
  return new Octokit({ auth: token });
1911
1476
  }
1477
+ function isGithbActionActionToken(token) {
1478
+ return token.startsWith("ghs_");
1479
+ }
1912
1480
  async function githubValidateParams(url, accessToken) {
1913
1481
  try {
1914
1482
  const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1915
1483
  if (accessToken) {
1916
- await oktoKit.rest.users.getAuthenticated();
1484
+ isGithbActionActionToken(accessToken) ? null : await oktoKit.rest.users.getAuthenticated();
1917
1485
  }
1918
1486
  if (url) {
1919
1487
  const { owner, repo } = parseGithubOwnerAndRepo(url);
1920
- await oktoKit.rest.repos.get({ repo, owner });
1488
+ await oktoKit.request("GET /repos/{owner}/{repo}/branches", {
1489
+ owner,
1490
+ repo,
1491
+ per_page: 1
1492
+ });
1921
1493
  }
1922
1494
  } catch (e) {
1495
+ console.log("could not init github scm", e);
1923
1496
  const error = e;
1924
1497
  const code = error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
1925
1498
  if (code === 401 || code === 403) {
@@ -2349,20 +1922,20 @@ import {
2349
1922
  Gitlab
2350
1923
  } from "@gitbeaker/rest";
2351
1924
  import { ProxyAgent } from "undici";
2352
- import { z as z6 } from "zod";
1925
+ import { z as z5 } from "zod";
2353
1926
 
2354
1927
  // src/features/analysis/scm/gitlab/types.ts
2355
- import { z as z5 } from "zod";
2356
- var GitlabAuthResultZ = z5.object({
2357
- access_token: z5.string(),
2358
- token_type: z5.string(),
2359
- refresh_token: z5.string()
1928
+ import { z as z4 } from "zod";
1929
+ var GitlabAuthResultZ = z4.object({
1930
+ access_token: z4.string(),
1931
+ token_type: z4.string(),
1932
+ refresh_token: z4.string()
2360
1933
  });
2361
1934
 
2362
1935
  // src/features/analysis/scm/gitlab/gitlab.ts
2363
- var EnvVariablesZod2 = z6.object({
2364
- GITLAB_API_TOKEN: z6.string().optional(),
2365
- BROKERED_HOSTS: z6.string().toLowerCase().transform(
1936
+ var EnvVariablesZod2 = z5.object({
1937
+ GITLAB_API_TOKEN: z5.string().optional(),
1938
+ BROKERED_HOSTS: z5.string().toLowerCase().transform(
2366
1939
  (x) => x.split(",").map((url) => url.trim(), []).filter(Boolean)
2367
1940
  ).default("")
2368
1941
  });
@@ -2659,92 +2232,92 @@ initGitlabFetchMock();
2659
2232
  import fs from "node:fs/promises";
2660
2233
  import parseDiff from "parse-diff";
2661
2234
  import path3 from "path";
2662
- import { simpleGit as simpleGit2 } from "simple-git";
2235
+ import { simpleGit } from "simple-git";
2663
2236
  import tmp from "tmp";
2664
- import { z as z8 } from "zod";
2237
+ import { z as z7 } from "zod";
2665
2238
 
2666
2239
  // src/features/analysis/scm/scmSubmit/types.ts
2667
- import { z as z7 } from "zod";
2668
- var BaseSubmitToScmMessageZ = z7.object({
2669
- submitFixRequestId: z7.string().uuid(),
2670
- fixes: z7.array(
2671
- z7.object({
2672
- fixId: z7.string().uuid(),
2673
- patches: z7.array(z7.string())
2240
+ import { z as z6 } from "zod";
2241
+ var BaseSubmitToScmMessageZ = z6.object({
2242
+ submitFixRequestId: z6.string().uuid(),
2243
+ fixes: z6.array(
2244
+ z6.object({
2245
+ fixId: z6.string().uuid(),
2246
+ patches: z6.array(z6.string())
2674
2247
  })
2675
2248
  ),
2676
- commitHash: z7.string(),
2677
- repoUrl: z7.string()
2249
+ commitHash: z6.string(),
2250
+ repoUrl: z6.string()
2678
2251
  });
2679
2252
  var submitToScmMessageType = {
2680
2253
  commitToSameBranch: "commitToSameBranch",
2681
2254
  submitFixesForDifferentBranch: "submitFixesForDifferentBranch"
2682
2255
  };
2683
2256
  var CommitToSameBranchParamsZ = BaseSubmitToScmMessageZ.merge(
2684
- z7.object({
2685
- type: z7.literal(submitToScmMessageType.commitToSameBranch),
2686
- branch: z7.string(),
2687
- commitMessage: z7.string(),
2688
- commitDescription: z7.string().nullish(),
2689
- githubCommentId: z7.number().nullish()
2257
+ z6.object({
2258
+ type: z6.literal(submitToScmMessageType.commitToSameBranch),
2259
+ branch: z6.string(),
2260
+ commitMessage: z6.string(),
2261
+ commitDescription: z6.string().nullish(),
2262
+ githubCommentId: z6.number().nullish()
2690
2263
  })
2691
2264
  );
2692
- var SubmitFixesToDifferentBranchParamsZ = z7.object({
2693
- type: z7.literal(submitToScmMessageType.submitFixesForDifferentBranch),
2694
- submitBranch: z7.string(),
2695
- baseBranch: z7.string()
2265
+ var SubmitFixesToDifferentBranchParamsZ = z6.object({
2266
+ type: z6.literal(submitToScmMessageType.submitFixesForDifferentBranch),
2267
+ submitBranch: z6.string(),
2268
+ baseBranch: z6.string()
2696
2269
  }).merge(BaseSubmitToScmMessageZ);
2697
- var SubmitFixesMessageZ = z7.union([
2270
+ var SubmitFixesMessageZ = z6.union([
2698
2271
  CommitToSameBranchParamsZ,
2699
2272
  SubmitFixesToDifferentBranchParamsZ
2700
2273
  ]);
2701
- var FixResponseArrayZ = z7.array(
2702
- z7.object({
2703
- fixId: z7.string().uuid()
2274
+ var FixResponseArrayZ = z6.array(
2275
+ z6.object({
2276
+ fixId: z6.string().uuid()
2704
2277
  })
2705
2278
  );
2706
- var SubmitFixesBaseResponseMessageZ = z7.object({
2707
- submitFixRequestId: z7.string().uuid(),
2708
- submitBranches: z7.array(
2709
- z7.object({
2710
- branchName: z7.string(),
2279
+ var SubmitFixesBaseResponseMessageZ = z6.object({
2280
+ submitFixRequestId: z6.string().uuid(),
2281
+ submitBranches: z6.array(
2282
+ z6.object({
2283
+ branchName: z6.string(),
2711
2284
  fixes: FixResponseArrayZ
2712
2285
  })
2713
2286
  ),
2714
- error: z7.object({
2715
- type: z7.enum([
2287
+ error: z6.object({
2288
+ type: z6.enum([
2716
2289
  "InitialRepoAccessError",
2717
2290
  "PushBranchError",
2718
2291
  "UnknownError"
2719
2292
  ]),
2720
- info: z7.object({
2721
- message: z7.string(),
2722
- pushBranchName: z7.string().optional()
2293
+ info: z6.object({
2294
+ message: z6.string(),
2295
+ pushBranchName: z6.string().optional()
2723
2296
  })
2724
2297
  }).optional()
2725
2298
  });
2726
- var SubmitFixesToSameBranchResponseMessageZ = z7.object({
2727
- type: z7.literal(submitToScmMessageType.commitToSameBranch),
2728
- githubCommentId: z7.number().nullish()
2299
+ var SubmitFixesToSameBranchResponseMessageZ = z6.object({
2300
+ type: z6.literal(submitToScmMessageType.commitToSameBranch),
2301
+ githubCommentId: z6.number().nullish()
2729
2302
  }).merge(SubmitFixesBaseResponseMessageZ);
2730
- var SubmitFixesToDifferentBranchResponseMessageZ = z7.object({
2731
- type: z7.literal(submitToScmMessageType.submitFixesForDifferentBranch),
2732
- githubCommentId: z7.number().optional()
2303
+ var SubmitFixesToDifferentBranchResponseMessageZ = z6.object({
2304
+ type: z6.literal(submitToScmMessageType.submitFixesForDifferentBranch),
2305
+ githubCommentId: z6.number().optional()
2733
2306
  }).merge(SubmitFixesBaseResponseMessageZ);
2734
- var SubmitFixesResponseMessageZ = z7.discriminatedUnion("type", [
2307
+ var SubmitFixesResponseMessageZ = z6.discriminatedUnion("type", [
2735
2308
  SubmitFixesToSameBranchResponseMessageZ,
2736
2309
  SubmitFixesToDifferentBranchResponseMessageZ
2737
2310
  ]);
2738
2311
 
2739
2312
  // src/features/analysis/scm/scmSubmit/index.ts
2740
- var EnvVariablesZod3 = z8.object({
2741
- BROKERED_HOSTS: z8.string().toLowerCase().transform(
2313
+ var EnvVariablesZod3 = z7.object({
2314
+ BROKERED_HOSTS: z7.string().toLowerCase().transform(
2742
2315
  (x) => x.split(",").map((url) => url.trim(), []).filter(Boolean)
2743
2316
  ).default("")
2744
2317
  });
2745
2318
  var { BROKERED_HOSTS: BROKERED_HOSTS2 } = EnvVariablesZod3.parse(process.env);
2746
2319
  var isValidBranchName = async (branchName) => {
2747
- const git = simpleGit2();
2320
+ const git = simpleGit();
2748
2321
  try {
2749
2322
  const res = await git.raw(["check-ref-format", "--branch", branchName]);
2750
2323
  if (res) {
@@ -2755,18 +2328,18 @@ var isValidBranchName = async (branchName) => {
2755
2328
  return false;
2756
2329
  }
2757
2330
  };
2758
- var FixesZ = z8.array(
2759
- z8.object({
2760
- fixId: z8.string(),
2761
- patches: z8.array(z8.string())
2331
+ var FixesZ = z7.array(
2332
+ z7.object({
2333
+ fixId: z7.string(),
2334
+ patches: z7.array(z7.string())
2762
2335
  })
2763
2336
  ).nonempty();
2764
2337
 
2765
2338
  // src/features/analysis/scm/scm.ts
2766
- var GetRefererenceResultZ = z9.object({
2767
- date: z9.date().optional(),
2768
- sha: z9.string(),
2769
- type: z9.nativeEnum(ReferenceType)
2339
+ var GetRefererenceResultZ = z8.object({
2340
+ date: z8.date().optional(),
2341
+ sha: z8.string(),
2342
+ type: z8.nativeEnum(ReferenceType)
2770
2343
  });
2771
2344
  function getCloudScmLibTypeFromUrl(url) {
2772
2345
  if (!url) {
@@ -2807,11 +2380,11 @@ var scmTypeToScmLibScmType = {
2807
2380
  ["Bitbucket" /* Bitbucket */]: "BITBUCKET" /* BITBUCKET */
2808
2381
  };
2809
2382
  function getScmTypeFromScmLibType(scmLibType) {
2810
- const parsedScmLibType = z9.nativeEnum(ScmLibScmType).parse(scmLibType);
2383
+ const parsedScmLibType = z8.nativeEnum(ScmLibScmType).parse(scmLibType);
2811
2384
  return scmLibScmTypeToScmType[parsedScmLibType];
2812
2385
  }
2813
2386
  function getScmLibTypeFromScmType(scmType) {
2814
- const parsedScmType = z9.nativeEnum(ScmType).parse(scmType);
2387
+ const parsedScmType = z8.nativeEnum(ScmType).parse(scmType);
2815
2388
  return scmTypeToScmLibScmType[parsedScmType];
2816
2389
  }
2817
2390
  function getScmConfig({
@@ -2904,8 +2477,9 @@ var RefNotFoundError = class extends Error {
2904
2477
  }
2905
2478
  };
2906
2479
  var RepoNoTokenAccessError = class extends Error {
2907
- constructor(m) {
2480
+ constructor(m, scmType) {
2908
2481
  super(m);
2482
+ this.scmType = scmType;
2909
2483
  }
2910
2484
  };
2911
2485
  function buildAuthrizedRepoUrl(args) {
@@ -3034,7 +2608,10 @@ var SCMLib = class {
3034
2608
  }
3035
2609
  } catch (e) {
3036
2610
  if (e instanceof InvalidRepoUrlError && url) {
3037
- throw new RepoNoTokenAccessError("no access to repo");
2611
+ throw new RepoNoTokenAccessError(
2612
+ "no access to repo",
2613
+ scmLibScmTypeToScmType[z8.nativeEnum(ScmLibScmType).parse(scmType)]
2614
+ );
3038
2615
  }
3039
2616
  }
3040
2617
  return new StubSCMLib(trimmedUrl, void 0, void 0);
@@ -3452,7 +3029,7 @@ var GithubSCMLib = class extends SCMLib {
3452
3029
  owner,
3453
3030
  repo
3454
3031
  });
3455
- return z9.string().parse(prRes.data);
3032
+ return z8.string().parse(prRes.data);
3456
3033
  }
3457
3034
  async getRepoList(_scmOrg) {
3458
3035
  if (!this.accessToken) {
@@ -3566,12 +3143,11 @@ var GithubSCMLib = class extends SCMLib {
3566
3143
  });
3567
3144
  return getPrRes.data.html_url;
3568
3145
  }
3569
- async postGeneralPrComment(params, auth) {
3146
+ async postGeneralPrComment(params) {
3570
3147
  const { prNumber, body } = params;
3571
3148
  this._validateUrl();
3572
- const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
3573
3149
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
3574
- return await postGeneralPrComment(oktoKit, {
3150
+ return await postGeneralPrComment(this.oktokit, {
3575
3151
  issue_number: prNumber,
3576
3152
  owner,
3577
3153
  repo,
@@ -3589,11 +3165,12 @@ var GithubSCMLib = class extends SCMLib {
3589
3165
  repo
3590
3166
  });
3591
3167
  }
3592
- async deleteGeneralPrComment({ commentId }, auth) {
3168
+ async deleteGeneralPrComment({
3169
+ commentId
3170
+ }) {
3593
3171
  this._validateUrl();
3594
- const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
3595
3172
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
3596
- return deleteGeneralPrComment(oktoKit, {
3173
+ return deleteGeneralPrComment(this.oktokit, {
3597
3174
  owner,
3598
3175
  repo,
3599
3176
  comment_id: commentId
@@ -3667,7 +3244,7 @@ var StubSCMLib = class extends SCMLib {
3667
3244
  };
3668
3245
  function getUserAndPassword(token) {
3669
3246
  const [username, password] = token.split(":");
3670
- const safePasswordAndUsername = z9.object({ username: z9.string(), password: z9.string() }).parse({ username, password });
3247
+ const safePasswordAndUsername = z8.object({ username: z8.string(), password: z8.string() }).parse({ username, password });
3671
3248
  return {
3672
3249
  username: safePasswordAndUsername.username,
3673
3250
  password: safePasswordAndUsername.password
@@ -3703,7 +3280,7 @@ var BitbucketSCMLib = class extends SCMLib {
3703
3280
  return { username, password, authType };
3704
3281
  }
3705
3282
  case "token": {
3706
- return { authType, token: z9.string().parse(this.accessToken) };
3283
+ return { authType, token: z8.string().parse(this.accessToken) };
3707
3284
  }
3708
3285
  case "public":
3709
3286
  return { authType };
@@ -3715,7 +3292,7 @@ var BitbucketSCMLib = class extends SCMLib {
3715
3292
  ...params,
3716
3293
  repoUrl: this.url
3717
3294
  });
3718
- return String(z9.number().parse(pullRequestRes.id));
3295
+ return String(z8.number().parse(pullRequestRes.id));
3719
3296
  }
3720
3297
  async validateParams() {
3721
3298
  return validateBitbucketParams({
@@ -3787,7 +3364,7 @@ var BitbucketSCMLib = class extends SCMLib {
3787
3364
  async getUsername() {
3788
3365
  this._validateToken();
3789
3366
  const res = await this.bitbucketSdk.getUser();
3790
- return z9.string().parse(res.username);
3367
+ return z8.string().parse(res.username);
3791
3368
  }
3792
3369
  async getSubmitRequestStatus(_scmSubmitRequestId) {
3793
3370
  this._validateAccessTokenAndUrl();
@@ -3816,7 +3393,7 @@ var BitbucketSCMLib = class extends SCMLib {
3816
3393
  async getRepoDefaultBranch() {
3817
3394
  this._validateUrl();
3818
3395
  const repoRes = await this.bitbucketSdk.getRepo({ repoUrl: this.url });
3819
- return z9.string().parse(repoRes.mainbranch?.name);
3396
+ return z8.string().parse(repoRes.mainbranch?.name);
3820
3397
  }
3821
3398
  getPrUrl(prNumber) {
3822
3399
  this._validateUrl();
@@ -3840,25 +3417,25 @@ var BitbucketSCMLib = class extends SCMLib {
3840
3417
  // src/features/analysis/scm/bitbucket/bitbucket.ts
3841
3418
  var { Bitbucket } = bitbucketPkg;
3842
3419
  var BITBUCKET_HOSTNAME = "bitbucket.org";
3843
- var TokenExpiredErrorZ = z10.object({
3844
- status: z10.number(),
3845
- error: z10.object({
3846
- type: z10.string(),
3847
- error: z10.object({
3848
- message: z10.string()
3420
+ var TokenExpiredErrorZ = z9.object({
3421
+ status: z9.number(),
3422
+ error: z9.object({
3423
+ type: z9.string(),
3424
+ error: z9.object({
3425
+ message: z9.string()
3849
3426
  })
3850
3427
  })
3851
3428
  });
3852
3429
  var BITBUCKET_ACCESS_TOKEN_URL = `https://${BITBUCKET_HOSTNAME}/site/oauth2/access_token`;
3853
- var BitbucketAuthResultZ = z10.object({
3854
- access_token: z10.string(),
3855
- token_type: z10.string(),
3856
- refresh_token: z10.string()
3430
+ var BitbucketAuthResultZ = z9.object({
3431
+ access_token: z9.string(),
3432
+ token_type: z9.string(),
3433
+ refresh_token: z9.string()
3857
3434
  });
3858
- var BitbucketParseResultZ = z10.object({
3859
- organization: z10.string(),
3860
- repoName: z10.string(),
3861
- hostname: z10.literal(BITBUCKET_HOSTNAME)
3435
+ var BitbucketParseResultZ = z9.object({
3436
+ organization: z9.string(),
3437
+ repoName: z9.string(),
3438
+ hostname: z9.literal(BITBUCKET_HOSTNAME)
3862
3439
  });
3863
3440
  function parseBitbucketOrganizationAndRepo(bitbucketUrl) {
3864
3441
  const parsedGitHubUrl = normalizeUrl(bitbucketUrl);
@@ -3936,7 +3513,7 @@ function getBitbucketSdk(params) {
3936
3513
  if (!res.data.values) {
3937
3514
  return [];
3938
3515
  }
3939
- return res.data.values.filter((branch) => !!branch.name).map((branch) => z10.string().parse(branch.name));
3516
+ return res.data.values.filter((branch) => !!branch.name).map((branch) => z9.string().parse(branch.name));
3940
3517
  },
3941
3518
  async getIsUserCollaborator(params2) {
3942
3519
  const { repoUrl } = params2;
@@ -4051,7 +3628,7 @@ function getBitbucketSdk(params) {
4051
3628
  return GetRefererenceResultZ.parse({
4052
3629
  sha: tagRes.data.target?.hash,
4053
3630
  type: "TAG" /* TAG */,
4054
- date: new Date(z10.string().parse(tagRes.data.target?.date))
3631
+ date: new Date(z9.string().parse(tagRes.data.target?.date))
4055
3632
  });
4056
3633
  },
4057
3634
  async getBranchRef(params2) {
@@ -4059,7 +3636,7 @@ function getBitbucketSdk(params) {
4059
3636
  return GetRefererenceResultZ.parse({
4060
3637
  sha: getBranchRes.target?.hash,
4061
3638
  type: "BRANCH" /* BRANCH */,
4062
- date: new Date(z10.string().parse(getBranchRes.target?.date))
3639
+ date: new Date(z9.string().parse(getBranchRes.target?.date))
4063
3640
  });
4064
3641
  },
4065
3642
  async getCommitRef(params2) {
@@ -4067,13 +3644,13 @@ function getBitbucketSdk(params) {
4067
3644
  return GetRefererenceResultZ.parse({
4068
3645
  sha: getCommitRes.hash,
4069
3646
  type: "COMMIT" /* COMMIT */,
4070
- date: new Date(z10.string().parse(getCommitRes.date))
3647
+ date: new Date(z9.string().parse(getCommitRes.date))
4071
3648
  });
4072
3649
  },
4073
3650
  async getDownloadUrl({ url, sha }) {
4074
3651
  this.getReferenceData({ ref: sha, url });
4075
3652
  const repoRes = await this.getRepo({ repoUrl: url });
4076
- const parsedRepoUrl = z10.string().url().parse(repoRes.links?.html?.href);
3653
+ const parsedRepoUrl = z9.string().url().parse(repoRes.links?.html?.href);
4077
3654
  return `${parsedRepoUrl}/get/${sha}.zip`;
4078
3655
  },
4079
3656
  async getPullRequest(params2) {
@@ -4116,7 +3693,7 @@ async function validateBitbucketParams(params) {
4116
3693
  }
4117
3694
  async function getUsersworkspacesSlugs(bitbucketClient) {
4118
3695
  const res = await bitbucketClient.workspaces.getWorkspaces({});
4119
- return res.data.values?.map((v) => z10.string().parse(v.slug));
3696
+ return res.data.values?.map((v) => z9.string().parse(v.slug));
4120
3697
  }
4121
3698
  async function getllUsersrepositories(bitbucketClient) {
4122
3699
  const userWorspacesSlugs = await getUsersworkspacesSlugs(bitbucketClient);
@@ -4144,7 +3721,11 @@ async function getRepositoriesByWorkspace(bitbucketClient, { workspaceSlug }) {
4144
3721
 
4145
3722
  // src/features/analysis/scm/constants.ts
4146
3723
  var MOBB_ICON_IMG = "https://app.mobb.ai/gh-action/Logo_Rounded_Icon.svg";
4147
- var COMMIT_FIX_SVG = `https://app.mobb.ai/gh-action/commit-button.svg`;
3724
+
3725
+ // src/features/analysis/add_fix_comments_for_pr/utils.ts
3726
+ import Debug3 from "debug";
3727
+ import parseDiff2 from "parse-diff";
3728
+ import { z as z10 } from "zod";
4148
3729
 
4149
3730
  // src/features/analysis/utils/by_key.ts
4150
3731
  function keyBy(array, keyBy2) {
@@ -4153,34 +3734,9 @@ function keyBy(array, keyBy2) {
4153
3734
  }, {});
4154
3735
  }
4155
3736
 
4156
- // src/features/analysis/utils/calculate_ranges.ts
4157
- function calculateRanges(integers) {
4158
- if (integers.length === 0) {
4159
- return [];
4160
- }
4161
- integers.sort((a, b) => a - b);
4162
- const ranges = integers.reduce(
4163
- (result, current, index) => {
4164
- if (index === 0) {
4165
- return [...result, [current, current]];
4166
- }
4167
- const currentRange = result[result.length - 1];
4168
- const [_start, end] = currentRange;
4169
- if (current === end + 1) {
4170
- currentRange[1] = current;
4171
- } else {
4172
- result.push([current, current]);
4173
- }
4174
- return result;
4175
- },
4176
- []
4177
- );
4178
- return ranges;
4179
- }
4180
-
4181
3737
  // src/features/analysis/utils/send_report.ts
4182
- import Debug4 from "debug";
4183
- var debug4 = Debug4("mobbdev:index");
3738
+ import Debug2 from "debug";
3739
+ var debug2 = Debug2("mobbdev:index");
4184
3740
  async function sendReport({
4185
3741
  spinner,
4186
3742
  submitVulnerabilityReportVariables,
@@ -4191,7 +3747,7 @@ async function sendReport({
4191
3747
  submitVulnerabilityReportVariables
4192
3748
  );
4193
3749
  if (submitRes.submitVulnerabilityReport.__typename !== "VulnerabilityReport") {
4194
- debug4("error submit vul report %s", submitRes);
3750
+ debug2("error submit vul report %s", submitRes);
4195
3751
  throw new Error("\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed");
4196
3752
  }
4197
3753
  spinner.update({ text: progressMassages.processingVulnerabilityReport });
@@ -4225,51 +3781,143 @@ function getFromArraySafe(array) {
4225
3781
  }, []);
4226
3782
  }
4227
3783
 
4228
- // src/features/analysis/handle_finished_analysis.ts
4229
- var debug5 = Debug5("mobbdev:handle-finished-analysis");
3784
+ // src/features/analysis/add_fix_comments_for_pr/constants.ts
4230
3785
  var contactUsMarkdown = `For specific requests [contact us](https://mobb.ai/contact) and we'll do the most to answer your need quickly.`;
4231
- var commitFixButton = (commitUrl) => `<a href="${commitUrl}"><img src=${COMMIT_FIX_SVG}></a>`;
4232
3786
  var MobbIconMarkdown = `![image](${MOBB_ICON_IMG})`;
4233
3787
  var noVulnerabilitiesFoundTitle = `# ${MobbIconMarkdown} No security issues were found \u2705`;
4234
- function scannerToFriendlyString(scanner) {
4235
- switch (scanner) {
4236
- case "checkmarx":
4237
- return "Checkmarx";
4238
- case "codeql":
4239
- return "CodeQL";
4240
- case "fortify":
4241
- return "Fortify";
4242
- case "snyk":
4243
- return "Snyk";
3788
+ var COMMIT_FIX_SVG = `https://app.mobb.ai/gh-action/commit-button.svg`;
3789
+ var scannerToFriendlyString = {
3790
+ checkmarx: "Checkmarx",
3791
+ codeql: "CodeQL",
3792
+ fortify: "Fortify",
3793
+ snyk: "Snyk"
3794
+ };
3795
+
3796
+ // src/features/analysis/add_fix_comments_for_pr/utils.ts
3797
+ var debug3 = Debug3("mobbdev:handle-finished-analysis");
3798
+ var getCommitFixButton = (commitUrl) => `<a href="${commitUrl}"><img src=${COMMIT_FIX_SVG}></a>`;
3799
+ function calculateRanges(integers) {
3800
+ if (integers.length === 0) {
3801
+ return [];
4244
3802
  }
3803
+ integers.sort((a, b) => a - b);
3804
+ const ranges = integers.reduce(
3805
+ (result, current, index) => {
3806
+ if (index === 0) {
3807
+ return [...result, [current, current]];
3808
+ }
3809
+ const currentRange = result[result.length - 1];
3810
+ const [_start, end] = currentRange;
3811
+ if (current === end + 1) {
3812
+ currentRange[1] = current;
3813
+ } else {
3814
+ result.push([current, current]);
3815
+ }
3816
+ return result;
3817
+ },
3818
+ []
3819
+ );
3820
+ return ranges;
4245
3821
  }
4246
- async function getRelevantVulenrabilitiesFromDiff(params) {
4247
- const { gqlClient, diff, vulnerabilityReportId } = params;
4248
- const parsedDiff = parseDiff2(diff);
4249
- const fileHunks = parsedDiff.map((file) => {
4250
- const fileNumbers = file.chunks.flatMap((chunk) => chunk.changes).filter((change) => change.type === "add").map((_change) => {
4251
- const change = _change;
4252
- return change.ln;
4253
- });
4254
- const lineAddedRanges = calculateRanges(fileNumbers);
4255
- const fileFilter = {
4256
- path: z11.string().parse(file.to),
4257
- ranges: lineAddedRanges.map(([startLine, endLine]) => ({
4258
- endLine,
4259
- startLine
4260
- }))
4261
- };
4262
- return fileFilter;
3822
+ function deleteAllPreviousComments({
3823
+ comments,
3824
+ scm
3825
+ }) {
3826
+ return comments.data.filter((comment) => {
3827
+ return comment.body.includes(MOBB_ICON_IMG);
3828
+ }).map((comment) => {
3829
+ try {
3830
+ return scm.deleteComment({ comment_id: comment.id });
3831
+ } catch (e) {
3832
+ debug3("delete comment failed %s", e);
3833
+ return Promise.resolve();
3834
+ }
4263
3835
  });
4264
- return gqlClient.getVulByNodesMetadata({
4265
- hunks: fileHunks,
4266
- vulnerabilityReportId
3836
+ }
3837
+ function deleteAllPreviousGeneralPrComments(params) {
3838
+ const { generalPrComments, scm } = params;
3839
+ return generalPrComments.data.filter((comment) => {
3840
+ if (!comment.body) {
3841
+ return false;
3842
+ }
3843
+ return comment.body.includes(MOBB_ICON_IMG);
3844
+ }).map((comment) => {
3845
+ try {
3846
+ return scm.deleteGeneralPrComment({ commentId: comment.id });
3847
+ } catch (e) {
3848
+ debug3("delete comment failed %s", e);
3849
+ return Promise.resolve();
3850
+ }
4267
3851
  });
4268
3852
  }
4269
- async function getFixesData(params) {
4270
- const { gqlClient, fixesId } = params;
4271
- const { fixes } = await gqlClient.getFixes(fixesId);
4272
- return keyBy(fixes, "id");
3853
+ async function postFixComment(params) {
3854
+ const {
3855
+ vulnerabilityReportIssueCodeNode,
3856
+ projectId,
3857
+ analysisId,
3858
+ organizationId,
3859
+ fixesById,
3860
+ scm,
3861
+ commitSha,
3862
+ pullRequest,
3863
+ scanner
3864
+ } = params;
3865
+ const {
3866
+ path: path9,
3867
+ startLine,
3868
+ vulnerabilityReportIssue: { fixId }
3869
+ } = vulnerabilityReportIssueCodeNode;
3870
+ const fix = fixesById[fixId];
3871
+ if (!fix || fix.patchAndQuestions.__typename !== "FixData") {
3872
+ throw new Error(`fix ${fixId} not found`);
3873
+ }
3874
+ const {
3875
+ patchAndQuestions: { patch }
3876
+ } = fix;
3877
+ const commentRes = await scm.postPrComment({
3878
+ body: "empty",
3879
+ pull_number: pullRequest,
3880
+ commit_id: commitSha,
3881
+ path: path9,
3882
+ line: startLine
3883
+ });
3884
+ const commentId = commentRes.data.id;
3885
+ const commitUrl = getCommitUrl({
3886
+ appBaseUrl: WEB_APP_URL,
3887
+ fixId,
3888
+ projectId,
3889
+ analysisId,
3890
+ organizationId,
3891
+ redirectUrl: commentRes.data.html_url,
3892
+ commentId
3893
+ });
3894
+ const fixUrl = getFixUrlWithRedirect({
3895
+ appBaseUrl: WEB_APP_URL,
3896
+ fixId,
3897
+ projectId,
3898
+ analysisId,
3899
+ organizationId,
3900
+ redirectUrl: commentRes.data.html_url,
3901
+ commentId
3902
+ });
3903
+ const scanerString = scannerToFriendlyString[scanner];
3904
+ const issueType = getIssueType(fix.issueType ?? null);
3905
+ const title = `# ${MobbIconMarkdown} ${issueType} fix is ready`;
3906
+ const subTitle = `### Apply the following code change to fix ${issueType} issue detected by **${scanerString}**:`;
3907
+ const diff = `\`\`\`diff
3908
+ ${patch}
3909
+ \`\`\``;
3910
+ const fixPageLink = `[Learn more and fine tune the fix](${fixUrl})`;
3911
+ return await scm.updatePrComment({
3912
+ body: `${title}
3913
+ ${subTitle}
3914
+ ${diff}
3915
+ ${getCommitFixButton(
3916
+ commitUrl
3917
+ )}
3918
+ ${fixPageLink}`,
3919
+ comment_id: commentId
3920
+ });
4273
3921
  }
4274
3922
  function buildAnalysisSummaryComment(params) {
4275
3923
  const { prVulenrabilities: fixesFromDiff, fixesById } = params;
@@ -4297,34 +3945,140 @@ function buildAnalysisSummaryComment(params) {
4297
3945
  return `${title}
4298
3946
  ${summary.join("\n")}`;
4299
3947
  }
4300
- async function handleFinishedAnalysis({
3948
+ async function getRelevantVulenrabilitiesFromDiff(params) {
3949
+ const { gqlClient, diff, vulnerabilityReportId } = params;
3950
+ const parsedDiff = parseDiff2(diff);
3951
+ const fileHunks = parsedDiff.map((file) => {
3952
+ const fileNumbers = file.chunks.flatMap((chunk) => chunk.changes).filter((change) => change.type === "add").map((_change) => {
3953
+ const change = _change;
3954
+ return change.ln;
3955
+ });
3956
+ const lineAddedRanges = calculateRanges(fileNumbers);
3957
+ const fileFilter = {
3958
+ path: z10.string().parse(file.to),
3959
+ ranges: lineAddedRanges.map(([startLine, endLine]) => ({
3960
+ endLine,
3961
+ startLine
3962
+ }))
3963
+ };
3964
+ return fileFilter;
3965
+ });
3966
+ return gqlClient.getVulByNodesMetadata({
3967
+ hunks: fileHunks,
3968
+ vulnerabilityReportId
3969
+ });
3970
+ }
3971
+ async function getFixesData(params) {
3972
+ const { gqlClient, fixesId } = params;
3973
+ const { fixes } = await gqlClient.getFixes(fixesId);
3974
+ return keyBy(fixes, "id");
3975
+ }
3976
+ async function postAnalysisSummary(params) {
3977
+ const { prVulenrabilities, fixesById, pullRequest, scm } = params;
3978
+ if (Object.values(fixesById).length === 0) {
3979
+ return;
3980
+ }
3981
+ const analysisSummaryComment = buildAnalysisSummaryComment({
3982
+ fixesById,
3983
+ prVulenrabilities
3984
+ });
3985
+ await scm.postGeneralPrComment({
3986
+ body: analysisSummaryComment,
3987
+ prNumber: pullRequest
3988
+ });
3989
+ }
3990
+ async function postAnalysisInsightComment(params) {
3991
+ const { prVulenrabilities, pullRequest, scanner, scm } = params;
3992
+ const scanerString = scannerToFriendlyString[scanner];
3993
+ const {
3994
+ totalPrVulnerabilities,
3995
+ vulnerabilitiesOutsidePr,
3996
+ fixablePrVuls,
3997
+ nonFixablePrVuls
3998
+ } = prVulenrabilities;
3999
+ debug3({
4000
+ fixablePrVuls,
4001
+ nonFixablePrVuls,
4002
+ vulnerabilitiesOutsidePr,
4003
+ totalPrVulnerabilities
4004
+ });
4005
+ if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr === 0) {
4006
+ const body = `Awesome! No vulnerabilities were found by **${scanerString}**`;
4007
+ const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
4008
+ ${body}`;
4009
+ await scm.postGeneralPrComment({
4010
+ body: noVulsFoundComment,
4011
+ prNumber: pullRequest
4012
+ });
4013
+ return;
4014
+ }
4015
+ if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr > 0) {
4016
+ const body = `Awesome! No vulnerabilities were found by **${scanerString}** in the changes made as part of this PR.`;
4017
+ const body2 = `Please notice there are issues in this repo that are unrelated to this PR.`;
4018
+ const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
4019
+ ${body}
4020
+ ${body2}`;
4021
+ await scm.postGeneralPrComment({
4022
+ body: noVulsFoundComment,
4023
+ prNumber: pullRequest
4024
+ });
4025
+ return;
4026
+ }
4027
+ if (fixablePrVuls === 0 && nonFixablePrVuls > 0) {
4028
+ const title = `# ${MobbIconMarkdown} We couldn't fix the issues detected by **${scanerString}**`;
4029
+ const body = `Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.`;
4030
+ const noFixableVulsComment = `${title}
4031
+ ${body}
4032
+ ${contactUsMarkdown}`;
4033
+ await scm.postGeneralPrComment({
4034
+ body: noFixableVulsComment,
4035
+ prNumber: pullRequest
4036
+ });
4037
+ return;
4038
+ }
4039
+ if (fixablePrVuls < nonFixablePrVuls && fixablePrVuls > 0) {
4040
+ const title = `# ${MobbIconMarkdown} We couldn't fix some of the issues detected by **${scanerString}**`;
4041
+ const body = "Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.";
4042
+ const fixableVulsComment = `${title}
4043
+ ${body}
4044
+ ${contactUsMarkdown}`;
4045
+ await scm.postGeneralPrComment({
4046
+ body: fixableVulsComment,
4047
+ prNumber: pullRequest
4048
+ });
4049
+ return;
4050
+ }
4051
+ }
4052
+
4053
+ // src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
4054
+ var debug4 = Debug4("mobbdev:handle-finished-analysis");
4055
+ async function addFixCommentsForPr({
4301
4056
  analysisId,
4302
4057
  scm: _scm,
4303
4058
  gqlClient,
4304
- githubActionToken,
4305
4059
  scanner
4306
4060
  }) {
4307
- const githubActionOctokit = new Octokit3({ auth: githubActionToken });
4308
4061
  if (_scm instanceof GithubSCMLib === false) {
4309
4062
  return;
4310
4063
  }
4311
4064
  const scm = _scm;
4312
- const getAnalysis = await gqlClient.getAnalysis(analysisId);
4065
+ const getAnalysisRes = await gqlClient.getAnalysis(analysisId);
4066
+ debug4("getAnalysis %o", getAnalysisRes);
4313
4067
  const {
4314
4068
  vulnerabilityReport: {
4315
4069
  projectId,
4316
4070
  project: { organizationId }
4317
4071
  }
4318
- } = getAnalysis;
4319
- if (!getAnalysis.repo || !getAnalysis.repo.commitSha || !getAnalysis.repo.pullRequest) {
4072
+ } = getAnalysisRes;
4073
+ if (!getAnalysisRes.repo || !getAnalysisRes.repo.commitSha || !getAnalysisRes.repo.pullRequest) {
4320
4074
  throw new Error("repo not found");
4321
4075
  }
4322
- const { commitSha, pullRequest } = getAnalysis.repo;
4076
+ const { commitSha, pullRequest } = getAnalysisRes.repo;
4323
4077
  const diff = await scm.getPrDiff({ pull_number: pullRequest });
4324
4078
  const prVulenrabilities = await getRelevantVulenrabilitiesFromDiff({
4325
4079
  diff,
4326
4080
  gqlClient,
4327
- vulnerabilityReportId: getAnalysis.vulnerabilityReportId
4081
+ vulnerabilityReportId: getAnalysisRes.vulnerabilityReportId
4328
4082
  });
4329
4083
  const { vulnerabilityReportIssueCodeNodes } = prVulenrabilities;
4330
4084
  const fixesId = vulnerabilityReportIssueCodeNodes.map(
@@ -4332,217 +4086,484 @@ async function handleFinishedAnalysis({
4332
4086
  );
4333
4087
  const fixesById = await getFixesData({ fixesId, gqlClient });
4334
4088
  const [comments, generalPrComments] = await Promise.all([
4335
- scm.getPrComments({ pull_number: pullRequest }, githubActionOctokit),
4336
- scm.getGeneralPrComments(
4337
- { prNumber: pullRequest },
4338
- { authToken: githubActionToken }
4339
- )
4089
+ scm.getPrComments({ pull_number: pullRequest }),
4090
+ scm.getGeneralPrComments({ prNumber: pullRequest })
4340
4091
  ]);
4341
- async function postAnalysisSummary() {
4342
- if (Object.values(fixesById).length === 0) {
4343
- return;
4092
+ await Promise.all([
4093
+ ...deleteAllPreviousComments({ comments, scm }),
4094
+ ...deleteAllPreviousGeneralPrComments({ generalPrComments, scm })
4095
+ ]);
4096
+ await Promise.all([
4097
+ ...prVulenrabilities.vulnerabilityReportIssueCodeNodes.map(
4098
+ (vulnerabilityReportIssueCodeNode) => {
4099
+ return postFixComment({
4100
+ vulnerabilityReportIssueCodeNode,
4101
+ projectId,
4102
+ analysisId,
4103
+ organizationId,
4104
+ fixesById,
4105
+ scm,
4106
+ pullRequest,
4107
+ scanner,
4108
+ commitSha
4109
+ });
4110
+ }
4111
+ ),
4112
+ postAnalysisInsightComment({
4113
+ prVulenrabilities,
4114
+ pullRequest,
4115
+ scanner,
4116
+ scm
4117
+ }),
4118
+ postAnalysisSummary({
4119
+ fixesById,
4120
+ prVulenrabilities,
4121
+ pullRequest,
4122
+ scm
4123
+ })
4124
+ ]);
4125
+ }
4126
+
4127
+ // src/features/analysis/git.ts
4128
+ import Debug5 from "debug";
4129
+ import { simpleGit as simpleGit2 } from "simple-git";
4130
+ var debug5 = Debug5("mobbdev:git");
4131
+ var GIT_NOT_INITIALIZED_ERROR_MESSAGE = "not a git repository";
4132
+ async function getGitInfo(srcDirPath) {
4133
+ debug5("getting git info for %s", srcDirPath);
4134
+ const git = simpleGit2({
4135
+ baseDir: srcDirPath,
4136
+ maxConcurrentProcesses: 1,
4137
+ trimmed: true
4138
+ });
4139
+ let repoUrl = "";
4140
+ let hash = "";
4141
+ let reference = "";
4142
+ try {
4143
+ repoUrl = (await git.getConfig("remote.origin.url")).value || "";
4144
+ hash = await git.revparse(["HEAD"]) || "";
4145
+ reference = await git.revparse(["--abbrev-ref", "HEAD"]) || "";
4146
+ } catch (e) {
4147
+ if (e instanceof Error) {
4148
+ debug5("failed to run git %o", e);
4149
+ if (e.message.includes(" spawn ")) {
4150
+ debug5("git cli not installed");
4151
+ } else if (e.message.includes(GIT_NOT_INITIALIZED_ERROR_MESSAGE)) {
4152
+ debug5("folder is not a git repo");
4153
+ return {
4154
+ success: false,
4155
+ hash: void 0,
4156
+ reference: void 0,
4157
+ repoUrl: void 0
4158
+ };
4159
+ } else {
4160
+ throw e;
4161
+ }
4162
+ }
4163
+ throw e;
4164
+ }
4165
+ if (repoUrl.endsWith(".git")) {
4166
+ repoUrl = repoUrl.slice(0, -".git".length);
4167
+ }
4168
+ if (repoUrl.startsWith("git@github.com:")) {
4169
+ repoUrl = repoUrl.replace("git@github.com:", "https://github.com/");
4170
+ }
4171
+ return {
4172
+ success: true,
4173
+ repoUrl,
4174
+ hash,
4175
+ reference
4176
+ };
4177
+ }
4178
+
4179
+ // src/features/analysis/graphql/gql.ts
4180
+ import Debug6 from "debug";
4181
+ import { GraphQLClient } from "graphql-request";
4182
+ import { v4 as uuidv4 } from "uuid";
4183
+
4184
+ // src/features/analysis/graphql/subscribe.ts
4185
+ import { createClient } from "graphql-ws";
4186
+ import WebSocket from "ws";
4187
+ var SUBSCRIPTION_TIMEOUT_MS = 10 * 60 * 1e3;
4188
+ function createWSClient(options) {
4189
+ return createClient({
4190
+ url: options.url,
4191
+ webSocketImpl: options.websocket || WebSocket,
4192
+ connectionParams: () => {
4193
+ return {
4194
+ headers: options.type === "apiKey" ? {
4195
+ [API_KEY_HEADER_NAME]: options.apiKey
4196
+ } : { authorization: `Bearer ${options.token}` }
4197
+ };
4198
+ }
4199
+ });
4200
+ }
4201
+ function subscribe(query, variables, callback, wsClientOptions) {
4202
+ return new Promise((resolve, reject) => {
4203
+ let timer = null;
4204
+ const { timeoutInMs = SUBSCRIPTION_TIMEOUT_MS } = wsClientOptions;
4205
+ const client = createWSClient({
4206
+ ...wsClientOptions,
4207
+ websocket: WebSocket,
4208
+ url: API_URL.replace("http", "ws")
4209
+ });
4210
+ const unsubscribe = client.subscribe(
4211
+ { query, variables },
4212
+ {
4213
+ next: (data) => {
4214
+ function callbackResolve(data2) {
4215
+ unsubscribe();
4216
+ if (timer) {
4217
+ clearTimeout(timer);
4218
+ }
4219
+ resolve(data2);
4220
+ }
4221
+ function callbackReject(data2) {
4222
+ unsubscribe();
4223
+ if (timer) {
4224
+ clearTimeout(timer);
4225
+ }
4226
+ reject(data2);
4227
+ }
4228
+ if (!data.data) {
4229
+ reject(
4230
+ new Error(
4231
+ `Broken data object from graphQL subscribe: ${JSON.stringify(
4232
+ data
4233
+ )} for query: ${query}`
4234
+ )
4235
+ );
4236
+ } else {
4237
+ callback(callbackResolve, callbackReject, data.data);
4238
+ }
4239
+ },
4240
+ error: (error) => {
4241
+ if (timer) {
4242
+ clearTimeout(timer);
4243
+ }
4244
+ reject(error);
4245
+ },
4246
+ complete: () => {
4247
+ return;
4248
+ }
4249
+ }
4250
+ );
4251
+ if (typeof timeoutInMs === "number") {
4252
+ timer = setTimeout(() => {
4253
+ unsubscribe();
4254
+ reject(
4255
+ new Error(
4256
+ `Timeout expired for graphQL subscribe query: ${query} with timeout: ${timeoutInMs}`
4257
+ )
4258
+ );
4259
+ }, timeoutInMs);
4260
+ }
4261
+ });
4262
+ }
4263
+
4264
+ // src/features/analysis/graphql/types.ts
4265
+ import { z as z11 } from "zod";
4266
+ var VulnerabilityReportIssueCodeNodeZ = z11.object({
4267
+ vulnerabilityReportIssueId: z11.string(),
4268
+ path: z11.string(),
4269
+ startLine: z11.number(),
4270
+ vulnerabilityReportIssue: z11.object({
4271
+ fixId: z11.string()
4272
+ })
4273
+ });
4274
+ var GetVulByNodesMetadataZ = z11.object({
4275
+ vulnerabilityReportIssueCodeNodes: z11.array(VulnerabilityReportIssueCodeNodeZ),
4276
+ nonFixablePrVuls: z11.object({
4277
+ aggregate: z11.object({
4278
+ count: z11.number()
4279
+ })
4280
+ }),
4281
+ fixablePrVuls: z11.object({
4282
+ aggregate: z11.object({
4283
+ count: z11.number()
4284
+ })
4285
+ }),
4286
+ totalScanVulnerabilities: z11.object({
4287
+ aggregate: z11.object({
4288
+ count: z11.number()
4289
+ })
4290
+ })
4291
+ });
4292
+
4293
+ // src/features/analysis/graphql/gql.ts
4294
+ var debug6 = Debug6("mobbdev:gql");
4295
+ var API_KEY_HEADER_NAME = "x-mobb-key";
4296
+ var REPORT_STATE_CHECK_DELAY = 5 * 1e3;
4297
+ var GQLClient = class {
4298
+ constructor(args) {
4299
+ __publicField(this, "_client");
4300
+ __publicField(this, "_clientSdk");
4301
+ __publicField(this, "_auth");
4302
+ debug6(`init with ${args}`);
4303
+ this._auth = args;
4304
+ this._client = new GraphQLClient(API_URL, {
4305
+ headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
4306
+ Authorization: `Bearer ${args.token}`
4307
+ },
4308
+ requestMiddleware: (request) => {
4309
+ const requestId = uuidv4();
4310
+ debug6(
4311
+ `sending API request with id: ${requestId} and with request: ${request.body}`
4312
+ );
4313
+ return {
4314
+ ...request,
4315
+ headers: {
4316
+ ...request.headers,
4317
+ "x-hasura-request-id": requestId
4318
+ }
4319
+ };
4320
+ }
4321
+ });
4322
+ this._clientSdk = getSdk(this._client);
4323
+ }
4324
+ async getUserInfo() {
4325
+ const { me } = await this._clientSdk.Me();
4326
+ return me;
4327
+ }
4328
+ async createCliLogin(variables) {
4329
+ const res = await this._clientSdk.CreateCliLogin(variables, {
4330
+ // We may have outdated API key in the config storage. Avoid using it for the login request.
4331
+ [API_KEY_HEADER_NAME]: ""
4332
+ });
4333
+ return res.insert_cli_login_one?.id || "";
4334
+ }
4335
+ async verifyToken() {
4336
+ await this.createCommunityUser();
4337
+ try {
4338
+ await this.getUserInfo();
4339
+ } catch (e) {
4340
+ debug6("verify token failed %o", e);
4341
+ return false;
4342
+ }
4343
+ return true;
4344
+ }
4345
+ async getOrgAndProjectId(projectName) {
4346
+ const getOrgAndProjectIdResult = await this._clientSdk.getOrgAndProjectId();
4347
+ const org = getOrgAndProjectIdResult?.users?.at(0)?.userOrganizationsAndUserOrganizationRoles?.at(0)?.organization;
4348
+ if (!org?.id) {
4349
+ throw new Error("Organization not found");
4350
+ }
4351
+ const project = projectName ? org?.projects.find((project2) => project2.name === projectName) ?? null : org?.projects[0];
4352
+ if (!project?.id) {
4353
+ throw new Error("Project not found");
4354
+ }
4355
+ let projectId = project?.id;
4356
+ if (!projectId) {
4357
+ const createdProject = await this._clientSdk.CreateProject({
4358
+ organizationId: org.id,
4359
+ projectName: projectName || "My project"
4360
+ });
4361
+ projectId = createdProject.createProject.projectId;
4362
+ }
4363
+ return {
4364
+ organizationId: org.id,
4365
+ projectId
4366
+ };
4367
+ }
4368
+ async getEncryptedApiToken(variables) {
4369
+ const res = await this._clientSdk.GetEncryptedApiToken(variables, {
4370
+ // We may have outdated API key in the config storage. Avoid using it for the login request.
4371
+ [API_KEY_HEADER_NAME]: ""
4372
+ });
4373
+ return res?.cli_login_by_pk?.encryptedApiToken || null;
4374
+ }
4375
+ async createCommunityUser() {
4376
+ try {
4377
+ await this._clientSdk.CreateCommunityUser();
4378
+ } catch (e) {
4379
+ debug6("create community user failed %o", e);
4344
4380
  }
4345
- const analysisSummaryComment = buildAnalysisSummaryComment({
4346
- fixesById,
4347
- prVulenrabilities
4381
+ }
4382
+ async updateScmToken(args) {
4383
+ const { scmType, url, token, org, username, refreshToken } = args;
4384
+ const updateScmTokenResult = await this._clientSdk.updateScmToken({
4385
+ scmType,
4386
+ url,
4387
+ token,
4388
+ org,
4389
+ username,
4390
+ refreshToken
4348
4391
  });
4349
- await scm.postGeneralPrComment(
4350
- {
4351
- body: analysisSummaryComment,
4352
- prNumber: pullRequest
4353
- },
4354
- { authToken: githubActionToken }
4355
- );
4392
+ return updateScmTokenResult;
4356
4393
  }
4357
- function deleteAllPreviousGeneralPrComments() {
4358
- return generalPrComments.data.filter((comment) => {
4359
- if (!comment.body) {
4360
- return false;
4361
- }
4362
- return comment.body.includes(MOBB_ICON_IMG);
4363
- }).map((comment) => {
4364
- try {
4365
- return scm.deleteGeneralPrComment(
4366
- { commentId: comment.id },
4367
- { authToken: githubActionToken }
4368
- );
4369
- } catch (e) {
4370
- debug5("delete comment failed %s", e);
4371
- return Promise.resolve();
4372
- }
4394
+ async uploadS3BucketInfo() {
4395
+ const uploadS3BucketInfoResult = await this._clientSdk.uploadS3BucketInfo({
4396
+ fileName: "report.json"
4373
4397
  });
4398
+ return uploadS3BucketInfoResult;
4374
4399
  }
4375
- function deleteAllPreviousComments() {
4376
- return comments.data.filter((comment) => {
4377
- return comment.body.includes(MOBB_ICON_IMG);
4378
- }).map((comment) => {
4379
- try {
4380
- return scm.deleteComment(
4381
- { comment_id: comment.id },
4382
- githubActionOctokit
4383
- );
4384
- } catch (e) {
4385
- debug5("delete comment failed %s", e);
4386
- return Promise.resolve();
4387
- }
4400
+ async getVulByNodesMetadata({
4401
+ hunks,
4402
+ vulnerabilityReportId
4403
+ }) {
4404
+ const filters = hunks.map((hunk) => {
4405
+ const filter = {
4406
+ path: { _eq: hunk.path },
4407
+ _or: hunk.ranges.flatMap(({ endLine, startLine }) => {
4408
+ return [
4409
+ { startLine: { _gte: startLine, _lte: endLine } },
4410
+ { endLine: { _gte: startLine, _lte: endLine } }
4411
+ ];
4412
+ })
4413
+ };
4414
+ return filter;
4415
+ });
4416
+ const getVulByNodesMetadataRes = await this._clientSdk.getVulByNodesMetadata({
4417
+ filters: { _or: filters },
4418
+ vulnerabilityReportId
4388
4419
  });
4420
+ const parsedGetVulByNodesMetadataRes = GetVulByNodesMetadataZ.parse(
4421
+ getVulByNodesMetadataRes
4422
+ );
4423
+ const uniqueVulByNodesMetadata = parsedGetVulByNodesMetadataRes.vulnerabilityReportIssueCodeNodes.reduce((acc, vulnerabilityReportIssueCodeNode) => {
4424
+ if (acc[vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]) {
4425
+ return acc;
4426
+ }
4427
+ return {
4428
+ ...acc,
4429
+ [vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]: vulnerabilityReportIssueCodeNode
4430
+ };
4431
+ }, {});
4432
+ const nonFixablePrVuls = parsedGetVulByNodesMetadataRes.nonFixablePrVuls.aggregate.count;
4433
+ const fixablePrVuls = parsedGetVulByNodesMetadataRes.fixablePrVuls.aggregate.count;
4434
+ const totalScanVulnerabilities = parsedGetVulByNodesMetadataRes.totalScanVulnerabilities.aggregate.count;
4435
+ const vulnerabilitiesOutsidePr = totalScanVulnerabilities - nonFixablePrVuls - fixablePrVuls;
4436
+ const totalPrVulnerabilities = nonFixablePrVuls + fixablePrVuls;
4437
+ return {
4438
+ vulnerabilityReportIssueCodeNodes: Object.values(
4439
+ uniqueVulByNodesMetadata
4440
+ ),
4441
+ nonFixablePrVuls,
4442
+ fixablePrVuls,
4443
+ totalScanVulnerabilities,
4444
+ vulnerabilitiesOutsidePr,
4445
+ totalPrVulnerabilities
4446
+ };
4389
4447
  }
4390
- await Promise.all([
4391
- ...deleteAllPreviousComments(),
4392
- ...deleteAllPreviousGeneralPrComments()
4393
- ]);
4394
- async function postFixComment(vulnerabilityReportIssueCodeNode) {
4395
- const {
4396
- path: path9,
4397
- startLine,
4398
- vulnerabilityReportIssue: { fixId }
4399
- } = vulnerabilityReportIssueCodeNode;
4400
- const fix = fixesById[fixId];
4401
- if (!fix || fix.patchAndQuestions.__typename !== "FixData") {
4402
- throw new Error(`fix ${fixId} not found`);
4448
+ async digestVulnerabilityReport({
4449
+ fixReportId,
4450
+ projectId,
4451
+ scanSource
4452
+ }) {
4453
+ const res = await this._clientSdk.DigestVulnerabilityReport({
4454
+ fixReportId,
4455
+ vulnerabilityReportFileName: "report.json",
4456
+ projectId,
4457
+ scanSource
4458
+ });
4459
+ if (res.digestVulnerabilityReport.__typename !== "VulnerabilityReport") {
4460
+ throw new Error("Digesting vulnerability report failed");
4403
4461
  }
4462
+ return res.digestVulnerabilityReport;
4463
+ }
4464
+ async submitVulnerabilityReport(params) {
4404
4465
  const {
4405
- patchAndQuestions: { patch }
4406
- } = fix;
4407
- const commentRes = await scm.postPrComment(
4408
- {
4409
- body: "empty",
4410
- pull_number: pullRequest,
4411
- commit_id: commitSha,
4412
- path: path9,
4413
- line: startLine
4414
- },
4415
- githubActionOctokit
4416
- );
4417
- const commentId = commentRes.data.id;
4418
- const commitUrl = getCommitUrl({
4419
- appBaseUrl: WEB_APP_URL,
4420
- fixId,
4466
+ fixReportId,
4467
+ repoUrl,
4468
+ reference,
4421
4469
  projectId,
4422
- analysisId,
4423
- organizationId,
4424
- redirectUrl: commentRes.data.html_url,
4425
- commentId
4426
- });
4427
- const fixUrl = getFixUrlWithRedirect({
4428
- appBaseUrl: WEB_APP_URL,
4429
- fixId,
4470
+ sha,
4471
+ experimentalEnabled,
4472
+ vulnerabilityReportFileName,
4473
+ pullRequest
4474
+ } = params;
4475
+ return await this._clientSdk.SubmitVulnerabilityReport({
4476
+ fixReportId,
4477
+ repoUrl,
4478
+ reference,
4479
+ vulnerabilityReportFileName,
4430
4480
  projectId,
4431
- analysisId,
4432
- organizationId,
4433
- redirectUrl: commentRes.data.html_url,
4434
- commentId
4481
+ pullRequest,
4482
+ sha: sha || "",
4483
+ experimentalEnabled,
4484
+ scanSource: params.scanSource
4435
4485
  });
4436
- const scanerString = scannerToFriendlyString(scanner);
4437
- const issueType = getIssueType(fix.issueType ?? null);
4438
- const title = `# ${MobbIconMarkdown} ${issueType} fix is ready`;
4439
- const subTitle = `### Apply the following code change to fix ${issueType} issue detected by **${scanerString}**:`;
4440
- const diff2 = `\`\`\`diff
4441
- ${patch}
4442
- \`\`\``;
4443
- const fixPageLink = `[Learn more and fine tune the fix](${fixUrl})`;
4444
- return await scm.updatePrComment(
4445
- {
4446
- body: `${title}
4447
- ${subTitle}
4448
- ${diff2}
4449
- ${commitFixButton(
4450
- commitUrl
4451
- )}
4452
- ${fixPageLink}`,
4453
- comment_id: commentId
4486
+ }
4487
+ async getFixReportState(fixReportId) {
4488
+ const res = await this._clientSdk.FixReportState({ id: fixReportId });
4489
+ return res?.fixReport_by_pk?.state || "Created" /* Created */;
4490
+ }
4491
+ async waitFixReportInit(fixReportId, includeDigested = false) {
4492
+ const FINAL_STATES = [
4493
+ "Finished" /* Finished */,
4494
+ "Failed" /* Failed */
4495
+ ];
4496
+ let lastState = "Created" /* Created */;
4497
+ let attempts = 100;
4498
+ if (includeDigested) {
4499
+ FINAL_STATES.push("Digested" /* Digested */);
4500
+ }
4501
+ do {
4502
+ await sleep(REPORT_STATE_CHECK_DELAY);
4503
+ lastState = await this.getFixReportState(fixReportId);
4504
+ } while (!FINAL_STATES.includes(
4505
+ lastState
4506
+ // wait for final the state of the fix report
4507
+ ) && attempts-- > 0);
4508
+ return lastState;
4509
+ }
4510
+ async getVulnerabilityReportPaths(vulnerabilityReportId) {
4511
+ const res = await this._clientSdk.GetVulnerabilityReportPaths({
4512
+ vulnerabilityReportId
4513
+ });
4514
+ return res.vulnerability_report_path.map((p) => p.path);
4515
+ }
4516
+ async subscribeToAnalysis(params) {
4517
+ const { callbackStates } = params;
4518
+ return subscribe(
4519
+ GetAnalysisDocument,
4520
+ params.subscribeToAnalysisParams,
4521
+ async (resolve, reject, data) => {
4522
+ if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
4523
+ reject(data);
4524
+ throw new Error(`Analysis failed with id: ${data.analysis?.id}`);
4525
+ }
4526
+ if (callbackStates.includes(data.analysis?.state)) {
4527
+ await params.callback(data.analysis.id);
4528
+ resolve(data);
4529
+ }
4454
4530
  },
4455
- githubActionOctokit
4531
+ this._auth.type === "apiKey" ? {
4532
+ apiKey: this._auth.apiKey,
4533
+ type: "apiKey",
4534
+ timeoutInMs: params.timeoutInMs
4535
+ } : {
4536
+ token: this._auth.token,
4537
+ type: "token",
4538
+ timeoutInMs: params.timeoutInMs
4539
+ }
4456
4540
  );
4457
4541
  }
4458
- async function postAnalysisInsightComment() {
4459
- const scanerString = scannerToFriendlyString(scanner);
4460
- const {
4461
- totalPrVulnerabilities,
4462
- vulnerabilitiesOutsidePr,
4463
- fixablePrVuls,
4464
- nonFixablePrVuls
4465
- } = prVulenrabilities;
4466
- debug5({
4467
- fixablePrVuls,
4468
- nonFixablePrVuls,
4469
- vulnerabilitiesOutsidePr,
4470
- totalPrVulnerabilities
4542
+ async getAnalysis(analysisId) {
4543
+ const res = await this._clientSdk.getAnalsyis({
4544
+ analysisId
4471
4545
  });
4472
- if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr === 0) {
4473
- const body = `Awesome! No vulnerabilities were found by **${scanerString}**`;
4474
- const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
4475
- ${body}`;
4476
- await scm.postGeneralPrComment(
4477
- {
4478
- body: noVulsFoundComment,
4479
- prNumber: pullRequest
4480
- },
4481
- { authToken: githubActionToken }
4482
- );
4483
- return;
4484
- }
4485
- if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr > 0) {
4486
- const body = `Awesome! No vulnerabilities were found by **${scanerString}** in the changes made as part of this PR.`;
4487
- const body2 = `Please notice there are issues in this repo that are unrelated to this PR.`;
4488
- const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
4489
- ${body}
4490
- ${body2}`;
4491
- await scm.postGeneralPrComment(
4492
- {
4493
- body: noVulsFoundComment,
4494
- prNumber: pullRequest
4495
- },
4496
- { authToken: githubActionToken }
4497
- );
4498
- return;
4499
- }
4500
- if (fixablePrVuls === 0 && nonFixablePrVuls > 0) {
4501
- const title = `# ${MobbIconMarkdown} We couldn't fix the issues detected by **${scanerString}**`;
4502
- const body = `Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.`;
4503
- const noFixableVulsComment = `${title}
4504
- ${body}
4505
- ${contactUsMarkdown}`;
4506
- await scm.postGeneralPrComment(
4507
- {
4508
- body: noFixableVulsComment,
4509
- prNumber: pullRequest
4510
- },
4511
- { authToken: githubActionToken }
4512
- );
4513
- return;
4514
- }
4515
- if (fixablePrVuls < nonFixablePrVuls && fixablePrVuls > 0) {
4516
- const title = `# ${MobbIconMarkdown} We couldn't fix some of the issues detected by **${scanerString}**`;
4517
- const body = "Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.";
4518
- const fixableVulsComment = `${title}
4519
- ${body}
4520
- ${contactUsMarkdown}`;
4521
- await scm.postGeneralPrComment(
4522
- {
4523
- body: fixableVulsComment,
4524
- prNumber: pullRequest
4525
- },
4526
- { authToken: githubActionToken }
4527
- );
4528
- return;
4546
+ if (!res.analysis) {
4547
+ throw new Error(`Analysis not found: ${analysisId}`);
4529
4548
  }
4549
+ return res.analysis;
4530
4550
  }
4531
- await Promise.all([
4532
- ...prVulenrabilities.vulnerabilityReportIssueCodeNodes.map(postFixComment),
4533
- postAnalysisInsightComment(),
4534
- postAnalysisSummary()
4535
- ]);
4536
- }
4551
+ async getFixes(fixIds) {
4552
+ const res = await this._clientSdk.getFixes({
4553
+ filters: { id: { _in: fixIds } }
4554
+ });
4555
+ return res;
4556
+ }
4557
+ };
4537
4558
 
4538
4559
  // src/features/analysis/pack.ts
4539
4560
  import fs2 from "node:fs";
4540
4561
  import path4 from "node:path";
4541
4562
  import AdmZip from "adm-zip";
4542
- import Debug6 from "debug";
4563
+ import Debug7 from "debug";
4543
4564
  import { globby } from "globby";
4544
4565
  import { isBinary } from "istextorbinary";
4545
- var debug6 = Debug6("mobbdev:pack");
4566
+ var debug7 = Debug7("mobbdev:pack");
4546
4567
  var MAX_FILE_SIZE = 1024 * 1024 * 5;
4547
4568
  function endsWithAny(str, suffixes) {
4548
4569
  return suffixes.some(function(suffix) {
@@ -4553,16 +4574,16 @@ function _get_manifest_files_suffixes() {
4553
4574
  return ["package.json"];
4554
4575
  }
4555
4576
  async function pack(srcDirPath, vulnFiles) {
4556
- debug6("pack folder %s", srcDirPath);
4577
+ debug7("pack folder %s", srcDirPath);
4557
4578
  const filepaths = await globby("**", {
4558
4579
  gitignore: true,
4559
4580
  onlyFiles: true,
4560
4581
  cwd: srcDirPath,
4561
4582
  followSymbolicLinks: false
4562
4583
  });
4563
- debug6("files found %d", filepaths.length);
4584
+ debug7("files found %d", filepaths.length);
4564
4585
  const zip = new AdmZip();
4565
- debug6("compressing files");
4586
+ debug7("compressing files");
4566
4587
  for (const filepath of filepaths) {
4567
4588
  const absFilepath = path4.join(srcDirPath, filepath.toString());
4568
4589
  vulnFiles = vulnFiles.concat(_get_manifest_files_suffixes());
@@ -4570,21 +4591,21 @@ async function pack(srcDirPath, vulnFiles) {
4570
4591
  absFilepath.toString().replaceAll(path4.win32.sep, path4.posix.sep),
4571
4592
  vulnFiles
4572
4593
  )) {
4573
- debug6("ignoring %s because it is not a vulnerability file", filepath);
4594
+ debug7("ignoring %s because it is not a vulnerability file", filepath);
4574
4595
  continue;
4575
4596
  }
4576
4597
  if (fs2.lstatSync(absFilepath).size > MAX_FILE_SIZE) {
4577
- debug6("ignoring %s because the size is > 5MB", filepath);
4598
+ debug7("ignoring %s because the size is > 5MB", filepath);
4578
4599
  continue;
4579
4600
  }
4580
4601
  const data = fs2.readFileSync(absFilepath);
4581
4602
  if (isBinary(null, data)) {
4582
- debug6("ignoring %s because is seems to be a binary file", filepath);
4603
+ debug7("ignoring %s because is seems to be a binary file", filepath);
4583
4604
  continue;
4584
4605
  }
4585
4606
  zip.addFile(filepath.toString(), data);
4586
4607
  }
4587
- debug6("get zip file buffer");
4608
+ debug7("get zip file buffer");
4588
4609
  return zip.toBuffer();
4589
4610
  }
4590
4611
 
@@ -4659,7 +4680,7 @@ var cxOperatingSystemSupportMessage = `Your operating system does not support ch
4659
4680
 
4660
4681
  // src/utils/child_process.ts
4661
4682
  import cp from "node:child_process";
4662
- import Debug7 from "debug";
4683
+ import Debug8 from "debug";
4663
4684
  import * as process2 from "process";
4664
4685
  import supportsColor from "supports-color";
4665
4686
  var { stdout: stdout2 } = supportsColor;
@@ -4678,16 +4699,16 @@ function createSpwan({ args, processPath, name }, options) {
4678
4699
  return createChildProcess({ childProcess: child, name }, options);
4679
4700
  }
4680
4701
  function createChildProcess({ childProcess, name }, options) {
4681
- const debug11 = Debug7(`mobbdev:${name}`);
4702
+ const debug12 = Debug8(`mobbdev:${name}`);
4682
4703
  const { display } = options;
4683
4704
  return new Promise((resolve, reject) => {
4684
4705
  let out = "";
4685
4706
  const onData = (chunk) => {
4686
- debug11(`chunk received from ${name} std ${chunk}`);
4707
+ debug12(`chunk received from ${name} std ${chunk}`);
4687
4708
  out += chunk;
4688
4709
  };
4689
4710
  if (!childProcess || !childProcess?.stdout || !childProcess?.stderr) {
4690
- debug11(`unable to fork ${name}`);
4711
+ debug12(`unable to fork ${name}`);
4691
4712
  reject(new Error(`unable to fork ${name}`));
4692
4713
  }
4693
4714
  childProcess.stdout?.on("data", onData);
@@ -4697,11 +4718,11 @@ function createChildProcess({ childProcess, name }, options) {
4697
4718
  childProcess.stderr?.pipe(process2.stderr);
4698
4719
  }
4699
4720
  childProcess.on("exit", (code) => {
4700
- debug11(`${name} exit code ${code}`);
4721
+ debug12(`${name} exit code ${code}`);
4701
4722
  resolve({ message: out, code });
4702
4723
  });
4703
4724
  childProcess.on("error", (err) => {
4704
- debug11(`${name} error %o`, err);
4725
+ debug12(`${name} error %o`, err);
4705
4726
  reject(err);
4706
4727
  });
4707
4728
  });
@@ -4709,12 +4730,12 @@ function createChildProcess({ childProcess, name }, options) {
4709
4730
 
4710
4731
  // src/features/analysis/scanners/checkmarx.ts
4711
4732
  import chalk2 from "chalk";
4712
- import Debug8 from "debug";
4733
+ import Debug9 from "debug";
4713
4734
  import { existsSync } from "fs";
4714
4735
  import { createSpinner as createSpinner2 } from "nanospinner";
4715
4736
  import { type } from "os";
4716
4737
  import path5 from "path";
4717
- var debug7 = Debug8("mobbdev:checkmarx");
4738
+ var debug8 = Debug9("mobbdev:checkmarx");
4718
4739
  var require2 = createRequire(import.meta.url);
4719
4740
  var getCheckmarxPath = () => {
4720
4741
  const os2 = type();
@@ -4755,14 +4776,14 @@ function validateCheckmarxInstallation() {
4755
4776
  existsSync(getCheckmarxPath());
4756
4777
  }
4757
4778
  async function forkCheckmarx(args, { display }) {
4758
- debug7("fork checkmarx with args %o %s", args.join(" "), display);
4779
+ debug8("fork checkmarx with args %o %s", args.join(" "), display);
4759
4780
  return createSpwan(
4760
4781
  { args, processPath: getCheckmarxPath(), name: "checkmarx" },
4761
4782
  { display }
4762
4783
  );
4763
4784
  }
4764
4785
  async function getCheckmarxReport({ reportPath, repositoryRoot, branch, projectName }, { skipPrompts = false }) {
4765
- debug7("get checkmarx report start %s %s", reportPath, repositoryRoot);
4786
+ debug8("get checkmarx report start %s %s", reportPath, repositoryRoot);
4766
4787
  const { code: loginCode } = await forkCheckmarx(VALIDATE_COMMAND, {
4767
4788
  display: false
4768
4789
  });
@@ -4830,23 +4851,23 @@ async function validateCheckamxCredentials() {
4830
4851
  // src/features/analysis/scanners/snyk.ts
4831
4852
  import { createRequire as createRequire2 } from "node:module";
4832
4853
  import chalk3 from "chalk";
4833
- import Debug9 from "debug";
4854
+ import Debug10 from "debug";
4834
4855
  import { createSpinner as createSpinner3 } from "nanospinner";
4835
4856
  import open from "open";
4836
- var debug8 = Debug9("mobbdev:snyk");
4857
+ var debug9 = Debug10("mobbdev:snyk");
4837
4858
  var require3 = createRequire2(import.meta.url);
4838
4859
  var SNYK_PATH = require3.resolve("snyk/bin/snyk");
4839
4860
  var SNYK_ARTICLE_URL = "https://docs.snyk.io/scan-application-code/snyk-code/getting-started-with-snyk-code/activating-snyk-code-using-the-web-ui/step-1-enabling-the-snyk-code-option";
4840
- debug8("snyk executable path %s", SNYK_PATH);
4861
+ debug9("snyk executable path %s", SNYK_PATH);
4841
4862
  async function forkSnyk(args, { display }) {
4842
- debug8("fork snyk with args %o %s", args, display);
4863
+ debug9("fork snyk with args %o %s", args, display);
4843
4864
  return createFork(
4844
4865
  { args, processPath: SNYK_PATH, name: "checkmarx" },
4845
4866
  { display }
4846
4867
  );
4847
4868
  }
4848
4869
  async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
4849
- debug8("get snyk report start %s %s", reportPath, repoRoot);
4870
+ debug9("get snyk report start %s %s", reportPath, repoRoot);
4850
4871
  const config4 = await forkSnyk(["config"], { display: false });
4851
4872
  const { message: configMessage } = config4;
4852
4873
  if (!configMessage.includes("api: ")) {
@@ -4860,7 +4881,7 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
4860
4881
  snykLoginSpinner.update({
4861
4882
  text: "\u{1F513} Waiting for Snyk login to complete"
4862
4883
  });
4863
- debug8("no token in the config %s", config4);
4884
+ debug9("no token in the config %s", config4);
4864
4885
  await forkSnyk(["auth"], { display: true });
4865
4886
  snykLoginSpinner.success({ text: "\u{1F513} Login to Snyk Successful" });
4866
4887
  }
@@ -4872,12 +4893,12 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
4872
4893
  if (scanOutput.includes(
4873
4894
  "Snyk Code is not supported for org: enable in Settings > Snyk Code"
4874
4895
  )) {
4875
- debug8("snyk code is not enabled %s", scanOutput);
4896
+ debug9("snyk code is not enabled %s", scanOutput);
4876
4897
  snykSpinner.error({ text: "\u{1F50D} Snyk configuration needed" });
4877
4898
  const answer = await snykArticlePrompt();
4878
- debug8("answer %s", answer);
4899
+ debug9("answer %s", answer);
4879
4900
  if (answer) {
4880
- debug8("opening the browser");
4901
+ debug9("opening the browser");
4881
4902
  await open(SNYK_ARTICLE_URL);
4882
4903
  }
4883
4904
  console.log(
@@ -4892,18 +4913,18 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
4892
4913
  }
4893
4914
 
4894
4915
  // src/features/analysis/upload-file.ts
4895
- import Debug10 from "debug";
4916
+ import Debug11 from "debug";
4896
4917
  import fetch2, { File, fileFrom, FormData } from "node-fetch";
4897
- var debug9 = Debug10("mobbdev:upload-file");
4918
+ var debug10 = Debug11("mobbdev:upload-file");
4898
4919
  async function uploadFile({
4899
4920
  file,
4900
4921
  url,
4901
4922
  uploadKey,
4902
4923
  uploadFields
4903
4924
  }) {
4904
- debug9("upload file start %s", url);
4905
- debug9("upload fields %o", uploadFields);
4906
- debug9("upload key %s", uploadKey);
4925
+ debug10("upload file start %s", url);
4926
+ debug10("upload fields %o", uploadFields);
4927
+ debug10("upload key %s", uploadKey);
4907
4928
  const form = new FormData();
4908
4929
  Object.entries(uploadFields).forEach(([key, value]) => {
4909
4930
  form.append(key, value);
@@ -4912,10 +4933,10 @@ async function uploadFile({
4912
4933
  form.append("key", uploadKey);
4913
4934
  }
4914
4935
  if (typeof file === "string") {
4915
- debug9("upload file from path %s", file);
4936
+ debug10("upload file from path %s", file);
4916
4937
  form.append("file", await fileFrom(file));
4917
4938
  } else {
4918
- debug9("upload file from buffer");
4939
+ debug10("upload file from buffer");
4919
4940
  form.append("file", new File([file], "file"));
4920
4941
  }
4921
4942
  const response = await fetch2(url, {
@@ -4923,10 +4944,10 @@ async function uploadFile({
4923
4944
  body: form
4924
4945
  });
4925
4946
  if (!response.ok) {
4926
- debug9("error from S3 %s %s", response.body, response.status);
4947
+ debug10("error from S3 %s %s", response.body, response.status);
4927
4948
  throw new Error(`Failed to upload the file: ${response.status}`);
4928
4949
  }
4929
- debug9("upload file done");
4950
+ debug10("upload file done");
4930
4951
  }
4931
4952
 
4932
4953
  // src/features/analysis/index.ts
@@ -4946,9 +4967,9 @@ async function downloadRepo({
4946
4967
  }) {
4947
4968
  const { createSpinner: createSpinner4 } = Spinner2({ ci });
4948
4969
  const repoSpinner = createSpinner4("\u{1F4BE} Downloading Repo").start();
4949
- debug10("download repo %s %s %s", repoUrl, dirname);
4970
+ debug11("download repo %s %s %s", repoUrl, dirname);
4950
4971
  const zipFilePath = path6.join(dirname, "repo.zip");
4951
- debug10("download URL: %s auth headers: %o", downloadUrl, authHeaders);
4972
+ debug11("download URL: %s auth headers: %o", downloadUrl, authHeaders);
4952
4973
  const response = await fetch3(downloadUrl, {
4953
4974
  method: "GET",
4954
4975
  headers: {
@@ -4956,7 +4977,7 @@ async function downloadRepo({
4956
4977
  }
4957
4978
  });
4958
4979
  if (!response.ok) {
4959
- debug10("SCM zipball request failed %s %s", response.body, response.status);
4980
+ debug11("SCM zipball request failed %s %s", response.body, response.status);
4960
4981
  repoSpinner.error({ text: "\u{1F4BE} Repo download failed" });
4961
4982
  throw new Error(`Can't access ${chalk4.bold(repoUrl)}`);
4962
4983
  }
@@ -4970,7 +4991,7 @@ async function downloadRepo({
4970
4991
  if (!repoRoot) {
4971
4992
  throw new Error("Repo root not found");
4972
4993
  }
4973
- debug10("repo root %s", repoRoot);
4994
+ debug11("repo root %s", repoRoot);
4974
4995
  repoSpinner.success({ text: "\u{1F4BE} Repo downloaded successfully" });
4975
4996
  return path6.join(dirname, repoRoot);
4976
4997
  }
@@ -4984,7 +5005,7 @@ var getReportUrl = ({
4984
5005
  projectId,
4985
5006
  fixReportId
4986
5007
  }) => `${WEB_APP_URL}/organization/${organizationId}/project/${projectId}/report/${fixReportId}`;
4987
- var debug10 = Debug11("mobbdev:index");
5008
+ var debug11 = Debug12("mobbdev:index");
4988
5009
  var packageJson = JSON.parse(
4989
5010
  fs3.readFileSync(path6.join(getDirName(), "../package.json"), "utf8")
4990
5011
  );
@@ -4994,7 +5015,7 @@ if (!semver.satisfies(process.version, packageJson.engines.node)) {
4994
5015
  );
4995
5016
  }
4996
5017
  var config2 = new Configstore(packageJson.name, { apiToken: "" });
4997
- debug10("config %o", config2);
5018
+ debug11("config %o", config2);
4998
5019
  async function runAnalysis(params, options) {
4999
5020
  const tmpObj = tmp2.dirSync({
5000
5021
  unsafeCleanup: true
@@ -5053,7 +5074,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
5053
5074
  githubToken: githubActionToken,
5054
5075
  command
5055
5076
  } = params;
5056
- debug10("start %s %s", dirname, repo);
5077
+ debug11("start %s %s", dirname, repo);
5057
5078
  const { createSpinner: createSpinner4 } = Spinner2({ ci });
5058
5079
  skipPrompts = skipPrompts || ci;
5059
5080
  let gqlClient = new GQLClient({
@@ -5125,9 +5146,9 @@ async function _scan(params, { skipPrompts = false } = {}) {
5125
5146
  const reference = ref ?? await scm.getRepoDefaultBranch();
5126
5147
  const { sha } = await scm.getReferenceData(reference);
5127
5148
  const downloadUrl = await scm.getDownloadUrl(sha);
5128
- debug10("org id %s", organizationId);
5129
- debug10("project id %s", projectId);
5130
- debug10("default branch %s", reference);
5149
+ debug11("org id %s", organizationId);
5150
+ debug11("project id %s", projectId);
5151
+ debug11("default branch %s", reference);
5131
5152
  const repositoryRoot = await downloadRepo({
5132
5153
  repoUrl: repo,
5133
5154
  dirname,
@@ -5174,21 +5195,6 @@ async function _scan(params, { skipPrompts = false } = {}) {
5174
5195
  mobbSpinner.error({ text: "\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed" });
5175
5196
  throw new Error("\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed");
5176
5197
  }
5177
- if (command === "review") {
5178
- await gqlClient.subscribeToAnalysis({
5179
- subscribeToAnalysisParams: {
5180
- analysisId: sendReportRes.submitVulnerabilityReport.fixReportId
5181
- },
5182
- callback: (analysisId) => handleFinishedAnalysis({
5183
- analysisId,
5184
- gqlClient,
5185
- scm,
5186
- githubActionToken: z12.string().parse(githubActionToken),
5187
- scanner: z12.nativeEnum(SCANNERS).parse(scanner)
5188
- }),
5189
- callbackStates: ["Finished" /* Finished */]
5190
- });
5191
- }
5192
5198
  mobbSpinner.success({
5193
5199
  text: "\u{1F575}\uFE0F\u200D\u2642\uFE0F Generating fixes..."
5194
5200
  });
@@ -5272,9 +5278,9 @@ async function _scan(params, { skipPrompts = false } = {}) {
5272
5278
  });
5273
5279
  loginSpinner.spin();
5274
5280
  if (encryptedApiToken) {
5275
- debug10("encrypted API token received %s", encryptedApiToken);
5281
+ debug11("encrypted API token received %s", encryptedApiToken);
5276
5282
  newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
5277
- debug10("API token decrypted");
5283
+ debug11("API token decrypted");
5278
5284
  break;
5279
5285
  }
5280
5286
  await sleep(LOGIN_CHECK_DELAY);
@@ -5287,7 +5293,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
5287
5293
  }
5288
5294
  gqlClient = new GQLClient({ apiKey: newApiToken, type: "apiKey" });
5289
5295
  if (await gqlClient.verifyToken()) {
5290
- debug10("set api token %s", newApiToken);
5296
+ debug11("set api token %s", newApiToken);
5291
5297
  config2.set("apiToken", newApiToken);
5292
5298
  loginSpinner.success({ text: "\u{1F513} Login to Mobb successful!" });
5293
5299
  } else {
@@ -5420,11 +5426,38 @@ async function _scan(params, { skipPrompts = false } = {}) {
5420
5426
  fixReportId: reportUploadInfo.fixReportId,
5421
5427
  projectId,
5422
5428
  repoUrl: repo || gitInfo.repoUrl || getTopLevelDirName(srcPath),
5423
- reference: gitInfo.reference || "no-branch",
5429
+ reference: ref || gitInfo.reference || "no-branch",
5424
5430
  sha: commitHash || gitInfo.hash || "0123456789abcdef",
5425
- scanSource: _getScanSource(command)
5431
+ scanSource: _getScanSource(command),
5432
+ pullRequest: params.pullRequest
5426
5433
  }
5427
5434
  });
5435
+ if (command === "review") {
5436
+ const params2 = z12.object({
5437
+ repo: z12.string().url(),
5438
+ githubActionToken: z12.string()
5439
+ }).parse({ repo, githubActionToken });
5440
+ const scm2 = await SCMLib.init({
5441
+ url: params2.repo,
5442
+ accessToken: params2.githubActionToken,
5443
+ scmOrg: "",
5444
+ scmType: "GITHUB" /* GITHUB */
5445
+ });
5446
+ await gqlClient.subscribeToAnalysis({
5447
+ subscribeToAnalysisParams: {
5448
+ analysisId: reportUploadInfo.fixReportId
5449
+ },
5450
+ callback: (analysisId) => {
5451
+ return addFixCommentsForPr({
5452
+ analysisId,
5453
+ gqlClient,
5454
+ scm: scm2,
5455
+ scanner: z12.nativeEnum(SCANNERS).parse(scanner)
5456
+ });
5457
+ },
5458
+ callbackStates: ["Finished" /* Finished */]
5459
+ });
5460
+ }
5428
5461
  } catch (e) {
5429
5462
  mobbSpinner2.error({ text: "\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed" });
5430
5463
  throw e;
@@ -5450,7 +5483,8 @@ async function review(params, { skipPrompts = true } = {}) {
5450
5483
  mobbProjectName,
5451
5484
  pullRequest,
5452
5485
  githubToken,
5453
- scanner
5486
+ scanner,
5487
+ srcPath
5454
5488
  } = params;
5455
5489
  await runAnalysis(
5456
5490
  {
@@ -5465,7 +5499,8 @@ async function review(params, { skipPrompts = true } = {}) {
5465
5499
  pullRequest,
5466
5500
  githubToken,
5467
5501
  scanner,
5468
- command: "review"
5502
+ command: "review",
5503
+ srcPath
5469
5504
  },
5470
5505
  { skipPrompts }
5471
5506
  );
@@ -5749,8 +5784,15 @@ function reviewBuilder(yargs2) {
5749
5784
  describe: chalk8.bold("Number of the pull request"),
5750
5785
  type: "number",
5751
5786
  demandOption: true
5787
+ }).option("p", {
5788
+ alias: "src-path",
5789
+ describe: chalk8.bold(
5790
+ "Path to the repository folder with the source code"
5791
+ ),
5792
+ type: "string",
5793
+ demandOption: true
5752
5794
  }).example(
5753
- "$0 review -r https://github.com/WebGoat/WebGoat -f <your_vulirabitliy_report_path> --ch <pr_last_commit> --pr <pr_number> --ref <pr_branch_name> --api-key <api_key>",
5795
+ "$0 review -r https://github.com/WebGoat/WebGoat -f <your_vulirabitliy_report_path> --ch <pr_last_commit> --pr <pr_number> --ref <pr_branch_name> --api-key <api_key> --src-path <your_repo_path>",
5754
5796
  "add fixes to your pr"
5755
5797
  ).help();
5756
5798
  }