mobbdev 0.0.130 → 0.0.134

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 +940 -897
  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,17 @@ 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
- followSymbolicLinks: false
4582
+ followSymbolicLinks: false,
4583
+ dot: true
4562
4584
  });
4563
- debug6("files found %d", filepaths.length);
4585
+ debug7("files found %d", filepaths.length);
4564
4586
  const zip = new AdmZip();
4565
- debug6("compressing files");
4587
+ debug7("compressing files");
4566
4588
  for (const filepath of filepaths) {
4567
4589
  const absFilepath = path4.join(srcDirPath, filepath.toString());
4568
4590
  vulnFiles = vulnFiles.concat(_get_manifest_files_suffixes());
@@ -4570,21 +4592,21 @@ async function pack(srcDirPath, vulnFiles) {
4570
4592
  absFilepath.toString().replaceAll(path4.win32.sep, path4.posix.sep),
4571
4593
  vulnFiles
4572
4594
  )) {
4573
- debug6("ignoring %s because it is not a vulnerability file", filepath);
4595
+ debug7("ignoring %s because it is not a vulnerability file", filepath);
4574
4596
  continue;
4575
4597
  }
4576
4598
  if (fs2.lstatSync(absFilepath).size > MAX_FILE_SIZE) {
4577
- debug6("ignoring %s because the size is > 5MB", filepath);
4599
+ debug7("ignoring %s because the size is > 5MB", filepath);
4578
4600
  continue;
4579
4601
  }
4580
4602
  const data = fs2.readFileSync(absFilepath);
4581
4603
  if (isBinary(null, data)) {
4582
- debug6("ignoring %s because is seems to be a binary file", filepath);
4604
+ debug7("ignoring %s because is seems to be a binary file", filepath);
4583
4605
  continue;
4584
4606
  }
4585
4607
  zip.addFile(filepath.toString(), data);
4586
4608
  }
4587
- debug6("get zip file buffer");
4609
+ debug7("get zip file buffer");
4588
4610
  return zip.toBuffer();
4589
4611
  }
4590
4612
 
@@ -4659,7 +4681,7 @@ var cxOperatingSystemSupportMessage = `Your operating system does not support ch
4659
4681
 
4660
4682
  // src/utils/child_process.ts
4661
4683
  import cp from "node:child_process";
4662
- import Debug7 from "debug";
4684
+ import Debug8 from "debug";
4663
4685
  import * as process2 from "process";
4664
4686
  import supportsColor from "supports-color";
4665
4687
  var { stdout: stdout2 } = supportsColor;
@@ -4678,16 +4700,16 @@ function createSpwan({ args, processPath, name }, options) {
4678
4700
  return createChildProcess({ childProcess: child, name }, options);
4679
4701
  }
4680
4702
  function createChildProcess({ childProcess, name }, options) {
4681
- const debug11 = Debug7(`mobbdev:${name}`);
4703
+ const debug12 = Debug8(`mobbdev:${name}`);
4682
4704
  const { display } = options;
4683
4705
  return new Promise((resolve, reject) => {
4684
4706
  let out = "";
4685
4707
  const onData = (chunk) => {
4686
- debug11(`chunk received from ${name} std ${chunk}`);
4708
+ debug12(`chunk received from ${name} std ${chunk}`);
4687
4709
  out += chunk;
4688
4710
  };
4689
4711
  if (!childProcess || !childProcess?.stdout || !childProcess?.stderr) {
4690
- debug11(`unable to fork ${name}`);
4712
+ debug12(`unable to fork ${name}`);
4691
4713
  reject(new Error(`unable to fork ${name}`));
4692
4714
  }
4693
4715
  childProcess.stdout?.on("data", onData);
@@ -4697,11 +4719,11 @@ function createChildProcess({ childProcess, name }, options) {
4697
4719
  childProcess.stderr?.pipe(process2.stderr);
4698
4720
  }
4699
4721
  childProcess.on("exit", (code) => {
4700
- debug11(`${name} exit code ${code}`);
4722
+ debug12(`${name} exit code ${code}`);
4701
4723
  resolve({ message: out, code });
4702
4724
  });
4703
4725
  childProcess.on("error", (err) => {
4704
- debug11(`${name} error %o`, err);
4726
+ debug12(`${name} error %o`, err);
4705
4727
  reject(err);
4706
4728
  });
4707
4729
  });
@@ -4709,12 +4731,12 @@ function createChildProcess({ childProcess, name }, options) {
4709
4731
 
4710
4732
  // src/features/analysis/scanners/checkmarx.ts
4711
4733
  import chalk2 from "chalk";
4712
- import Debug8 from "debug";
4734
+ import Debug9 from "debug";
4713
4735
  import { existsSync } from "fs";
4714
4736
  import { createSpinner as createSpinner2 } from "nanospinner";
4715
4737
  import { type } from "os";
4716
4738
  import path5 from "path";
4717
- var debug7 = Debug8("mobbdev:checkmarx");
4739
+ var debug8 = Debug9("mobbdev:checkmarx");
4718
4740
  var require2 = createRequire(import.meta.url);
4719
4741
  var getCheckmarxPath = () => {
4720
4742
  const os2 = type();
@@ -4755,14 +4777,14 @@ function validateCheckmarxInstallation() {
4755
4777
  existsSync(getCheckmarxPath());
4756
4778
  }
4757
4779
  async function forkCheckmarx(args, { display }) {
4758
- debug7("fork checkmarx with args %o %s", args.join(" "), display);
4780
+ debug8("fork checkmarx with args %o %s", args.join(" "), display);
4759
4781
  return createSpwan(
4760
4782
  { args, processPath: getCheckmarxPath(), name: "checkmarx" },
4761
4783
  { display }
4762
4784
  );
4763
4785
  }
4764
4786
  async function getCheckmarxReport({ reportPath, repositoryRoot, branch, projectName }, { skipPrompts = false }) {
4765
- debug7("get checkmarx report start %s %s", reportPath, repositoryRoot);
4787
+ debug8("get checkmarx report start %s %s", reportPath, repositoryRoot);
4766
4788
  const { code: loginCode } = await forkCheckmarx(VALIDATE_COMMAND, {
4767
4789
  display: false
4768
4790
  });
@@ -4830,23 +4852,23 @@ async function validateCheckamxCredentials() {
4830
4852
  // src/features/analysis/scanners/snyk.ts
4831
4853
  import { createRequire as createRequire2 } from "node:module";
4832
4854
  import chalk3 from "chalk";
4833
- import Debug9 from "debug";
4855
+ import Debug10 from "debug";
4834
4856
  import { createSpinner as createSpinner3 } from "nanospinner";
4835
4857
  import open from "open";
4836
- var debug8 = Debug9("mobbdev:snyk");
4858
+ var debug9 = Debug10("mobbdev:snyk");
4837
4859
  var require3 = createRequire2(import.meta.url);
4838
4860
  var SNYK_PATH = require3.resolve("snyk/bin/snyk");
4839
4861
  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);
4862
+ debug9("snyk executable path %s", SNYK_PATH);
4841
4863
  async function forkSnyk(args, { display }) {
4842
- debug8("fork snyk with args %o %s", args, display);
4864
+ debug9("fork snyk with args %o %s", args, display);
4843
4865
  return createFork(
4844
4866
  { args, processPath: SNYK_PATH, name: "checkmarx" },
4845
4867
  { display }
4846
4868
  );
4847
4869
  }
4848
4870
  async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
4849
- debug8("get snyk report start %s %s", reportPath, repoRoot);
4871
+ debug9("get snyk report start %s %s", reportPath, repoRoot);
4850
4872
  const config4 = await forkSnyk(["config"], { display: false });
4851
4873
  const { message: configMessage } = config4;
4852
4874
  if (!configMessage.includes("api: ")) {
@@ -4860,7 +4882,7 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
4860
4882
  snykLoginSpinner.update({
4861
4883
  text: "\u{1F513} Waiting for Snyk login to complete"
4862
4884
  });
4863
- debug8("no token in the config %s", config4);
4885
+ debug9("no token in the config %s", config4);
4864
4886
  await forkSnyk(["auth"], { display: true });
4865
4887
  snykLoginSpinner.success({ text: "\u{1F513} Login to Snyk Successful" });
4866
4888
  }
@@ -4872,12 +4894,12 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
4872
4894
  if (scanOutput.includes(
4873
4895
  "Snyk Code is not supported for org: enable in Settings > Snyk Code"
4874
4896
  )) {
4875
- debug8("snyk code is not enabled %s", scanOutput);
4897
+ debug9("snyk code is not enabled %s", scanOutput);
4876
4898
  snykSpinner.error({ text: "\u{1F50D} Snyk configuration needed" });
4877
4899
  const answer = await snykArticlePrompt();
4878
- debug8("answer %s", answer);
4900
+ debug9("answer %s", answer);
4879
4901
  if (answer) {
4880
- debug8("opening the browser");
4902
+ debug9("opening the browser");
4881
4903
  await open(SNYK_ARTICLE_URL);
4882
4904
  }
4883
4905
  console.log(
@@ -4892,18 +4914,18 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
4892
4914
  }
4893
4915
 
4894
4916
  // src/features/analysis/upload-file.ts
4895
- import Debug10 from "debug";
4917
+ import Debug11 from "debug";
4896
4918
  import fetch2, { File, fileFrom, FormData } from "node-fetch";
4897
- var debug9 = Debug10("mobbdev:upload-file");
4919
+ var debug10 = Debug11("mobbdev:upload-file");
4898
4920
  async function uploadFile({
4899
4921
  file,
4900
4922
  url,
4901
4923
  uploadKey,
4902
4924
  uploadFields
4903
4925
  }) {
4904
- debug9("upload file start %s", url);
4905
- debug9("upload fields %o", uploadFields);
4906
- debug9("upload key %s", uploadKey);
4926
+ debug10("upload file start %s", url);
4927
+ debug10("upload fields %o", uploadFields);
4928
+ debug10("upload key %s", uploadKey);
4907
4929
  const form = new FormData();
4908
4930
  Object.entries(uploadFields).forEach(([key, value]) => {
4909
4931
  form.append(key, value);
@@ -4912,10 +4934,10 @@ async function uploadFile({
4912
4934
  form.append("key", uploadKey);
4913
4935
  }
4914
4936
  if (typeof file === "string") {
4915
- debug9("upload file from path %s", file);
4937
+ debug10("upload file from path %s", file);
4916
4938
  form.append("file", await fileFrom(file));
4917
4939
  } else {
4918
- debug9("upload file from buffer");
4940
+ debug10("upload file from buffer");
4919
4941
  form.append("file", new File([file], "file"));
4920
4942
  }
4921
4943
  const response = await fetch2(url, {
@@ -4923,10 +4945,10 @@ async function uploadFile({
4923
4945
  body: form
4924
4946
  });
4925
4947
  if (!response.ok) {
4926
- debug9("error from S3 %s %s", response.body, response.status);
4948
+ debug10("error from S3 %s %s", response.body, response.status);
4927
4949
  throw new Error(`Failed to upload the file: ${response.status}`);
4928
4950
  }
4929
- debug9("upload file done");
4951
+ debug10("upload file done");
4930
4952
  }
4931
4953
 
4932
4954
  // src/features/analysis/index.ts
@@ -4946,9 +4968,9 @@ async function downloadRepo({
4946
4968
  }) {
4947
4969
  const { createSpinner: createSpinner4 } = Spinner2({ ci });
4948
4970
  const repoSpinner = createSpinner4("\u{1F4BE} Downloading Repo").start();
4949
- debug10("download repo %s %s %s", repoUrl, dirname);
4971
+ debug11("download repo %s %s %s", repoUrl, dirname);
4950
4972
  const zipFilePath = path6.join(dirname, "repo.zip");
4951
- debug10("download URL: %s auth headers: %o", downloadUrl, authHeaders);
4973
+ debug11("download URL: %s auth headers: %o", downloadUrl, authHeaders);
4952
4974
  const response = await fetch3(downloadUrl, {
4953
4975
  method: "GET",
4954
4976
  headers: {
@@ -4956,7 +4978,7 @@ async function downloadRepo({
4956
4978
  }
4957
4979
  });
4958
4980
  if (!response.ok) {
4959
- debug10("SCM zipball request failed %s %s", response.body, response.status);
4981
+ debug11("SCM zipball request failed %s %s", response.body, response.status);
4960
4982
  repoSpinner.error({ text: "\u{1F4BE} Repo download failed" });
4961
4983
  throw new Error(`Can't access ${chalk4.bold(repoUrl)}`);
4962
4984
  }
@@ -4970,7 +4992,7 @@ async function downloadRepo({
4970
4992
  if (!repoRoot) {
4971
4993
  throw new Error("Repo root not found");
4972
4994
  }
4973
- debug10("repo root %s", repoRoot);
4995
+ debug11("repo root %s", repoRoot);
4974
4996
  repoSpinner.success({ text: "\u{1F4BE} Repo downloaded successfully" });
4975
4997
  return path6.join(dirname, repoRoot);
4976
4998
  }
@@ -4984,7 +5006,7 @@ var getReportUrl = ({
4984
5006
  projectId,
4985
5007
  fixReportId
4986
5008
  }) => `${WEB_APP_URL}/organization/${organizationId}/project/${projectId}/report/${fixReportId}`;
4987
- var debug10 = Debug11("mobbdev:index");
5009
+ var debug11 = Debug12("mobbdev:index");
4988
5010
  var packageJson = JSON.parse(
4989
5011
  fs3.readFileSync(path6.join(getDirName(), "../package.json"), "utf8")
4990
5012
  );
@@ -4994,7 +5016,7 @@ if (!semver.satisfies(process.version, packageJson.engines.node)) {
4994
5016
  );
4995
5017
  }
4996
5018
  var config2 = new Configstore(packageJson.name, { apiToken: "" });
4997
- debug10("config %o", config2);
5019
+ debug11("config %o", config2);
4998
5020
  async function runAnalysis(params, options) {
4999
5021
  const tmpObj = tmp2.dirSync({
5000
5022
  unsafeCleanup: true
@@ -5053,7 +5075,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
5053
5075
  githubToken: githubActionToken,
5054
5076
  command
5055
5077
  } = params;
5056
- debug10("start %s %s", dirname, repo);
5078
+ debug11("start %s %s", dirname, repo);
5057
5079
  const { createSpinner: createSpinner4 } = Spinner2({ ci });
5058
5080
  skipPrompts = skipPrompts || ci;
5059
5081
  let gqlClient = new GQLClient({
@@ -5125,9 +5147,9 @@ async function _scan(params, { skipPrompts = false } = {}) {
5125
5147
  const reference = ref ?? await scm.getRepoDefaultBranch();
5126
5148
  const { sha } = await scm.getReferenceData(reference);
5127
5149
  const downloadUrl = await scm.getDownloadUrl(sha);
5128
- debug10("org id %s", organizationId);
5129
- debug10("project id %s", projectId);
5130
- debug10("default branch %s", reference);
5150
+ debug11("org id %s", organizationId);
5151
+ debug11("project id %s", projectId);
5152
+ debug11("default branch %s", reference);
5131
5153
  const repositoryRoot = await downloadRepo({
5132
5154
  repoUrl: repo,
5133
5155
  dirname,
@@ -5174,21 +5196,6 @@ async function _scan(params, { skipPrompts = false } = {}) {
5174
5196
  mobbSpinner.error({ text: "\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed" });
5175
5197
  throw new Error("\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed");
5176
5198
  }
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
5199
  mobbSpinner.success({
5193
5200
  text: "\u{1F575}\uFE0F\u200D\u2642\uFE0F Generating fixes..."
5194
5201
  });
@@ -5272,9 +5279,9 @@ async function _scan(params, { skipPrompts = false } = {}) {
5272
5279
  });
5273
5280
  loginSpinner.spin();
5274
5281
  if (encryptedApiToken) {
5275
- debug10("encrypted API token received %s", encryptedApiToken);
5282
+ debug11("encrypted API token received %s", encryptedApiToken);
5276
5283
  newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
5277
- debug10("API token decrypted");
5284
+ debug11("API token decrypted");
5278
5285
  break;
5279
5286
  }
5280
5287
  await sleep(LOGIN_CHECK_DELAY);
@@ -5287,7 +5294,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
5287
5294
  }
5288
5295
  gqlClient = new GQLClient({ apiKey: newApiToken, type: "apiKey" });
5289
5296
  if (await gqlClient.verifyToken()) {
5290
- debug10("set api token %s", newApiToken);
5297
+ debug11("set api token %s", newApiToken);
5291
5298
  config2.set("apiToken", newApiToken);
5292
5299
  loginSpinner.success({ text: "\u{1F513} Login to Mobb successful!" });
5293
5300
  } else {
@@ -5420,11 +5427,38 @@ async function _scan(params, { skipPrompts = false } = {}) {
5420
5427
  fixReportId: reportUploadInfo.fixReportId,
5421
5428
  projectId,
5422
5429
  repoUrl: repo || gitInfo.repoUrl || getTopLevelDirName(srcPath),
5423
- reference: gitInfo.reference || "no-branch",
5430
+ reference: ref || gitInfo.reference || "no-branch",
5424
5431
  sha: commitHash || gitInfo.hash || "0123456789abcdef",
5425
- scanSource: _getScanSource(command)
5432
+ scanSource: _getScanSource(command),
5433
+ pullRequest: params.pullRequest
5426
5434
  }
5427
5435
  });
5436
+ if (command === "review") {
5437
+ const params2 = z12.object({
5438
+ repo: z12.string().url(),
5439
+ githubActionToken: z12.string()
5440
+ }).parse({ repo, githubActionToken });
5441
+ const scm2 = await SCMLib.init({
5442
+ url: params2.repo,
5443
+ accessToken: params2.githubActionToken,
5444
+ scmOrg: "",
5445
+ scmType: "GITHUB" /* GITHUB */
5446
+ });
5447
+ await gqlClient.subscribeToAnalysis({
5448
+ subscribeToAnalysisParams: {
5449
+ analysisId: reportUploadInfo.fixReportId
5450
+ },
5451
+ callback: (analysisId) => {
5452
+ return addFixCommentsForPr({
5453
+ analysisId,
5454
+ gqlClient,
5455
+ scm: scm2,
5456
+ scanner: z12.nativeEnum(SCANNERS).parse(scanner)
5457
+ });
5458
+ },
5459
+ callbackStates: ["Finished" /* Finished */]
5460
+ });
5461
+ }
5428
5462
  } catch (e) {
5429
5463
  mobbSpinner2.error({ text: "\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed" });
5430
5464
  throw e;
@@ -5450,7 +5484,8 @@ async function review(params, { skipPrompts = true } = {}) {
5450
5484
  mobbProjectName,
5451
5485
  pullRequest,
5452
5486
  githubToken,
5453
- scanner
5487
+ scanner,
5488
+ srcPath
5454
5489
  } = params;
5455
5490
  await runAnalysis(
5456
5491
  {
@@ -5465,7 +5500,8 @@ async function review(params, { skipPrompts = true } = {}) {
5465
5500
  pullRequest,
5466
5501
  githubToken,
5467
5502
  scanner,
5468
- command: "review"
5503
+ command: "review",
5504
+ srcPath
5469
5505
  },
5470
5506
  { skipPrompts }
5471
5507
  );
@@ -5749,8 +5785,15 @@ function reviewBuilder(yargs2) {
5749
5785
  describe: chalk8.bold("Number of the pull request"),
5750
5786
  type: "number",
5751
5787
  demandOption: true
5788
+ }).option("p", {
5789
+ alias: "src-path",
5790
+ describe: chalk8.bold(
5791
+ "Path to the repository folder with the source code"
5792
+ ),
5793
+ type: "string",
5794
+ demandOption: true
5752
5795
  }).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>",
5796
+ "$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
5797
  "add fixes to your pr"
5755
5798
  ).help();
5756
5799
  }