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.
- package/dist/index.mjs +940 -897
- 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
|
|
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/
|
|
964
|
-
import
|
|
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
|
|
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 =
|
|
1152
|
-
displayName:
|
|
1153
|
-
publicAlias:
|
|
1154
|
-
emailAddress:
|
|
1155
|
-
coreRevision:
|
|
1156
|
-
timeStamp:
|
|
1157
|
-
id:
|
|
1158
|
-
revision:
|
|
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 =
|
|
1161
|
-
count:
|
|
1162
|
-
value:
|
|
1163
|
-
|
|
1164
|
-
accountId:
|
|
1165
|
-
accountUri:
|
|
1166
|
-
accountName:
|
|
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 =
|
|
1598
|
-
access_token:
|
|
1599
|
-
token_type:
|
|
1600
|
-
refresh_token:
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
1870
|
-
GITHUB_API_TOKEN:
|
|
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.
|
|
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
|
|
1925
|
+
import { z as z5 } from "zod";
|
|
2353
1926
|
|
|
2354
1927
|
// src/features/analysis/scm/gitlab/types.ts
|
|
2355
|
-
import { z as
|
|
2356
|
-
var GitlabAuthResultZ =
|
|
2357
|
-
access_token:
|
|
2358
|
-
token_type:
|
|
2359
|
-
refresh_token:
|
|
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 =
|
|
2364
|
-
GITLAB_API_TOKEN:
|
|
2365
|
-
BROKERED_HOSTS:
|
|
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
|
|
2235
|
+
import { simpleGit } from "simple-git";
|
|
2663
2236
|
import tmp from "tmp";
|
|
2664
|
-
import { z as
|
|
2237
|
+
import { z as z7 } from "zod";
|
|
2665
2238
|
|
|
2666
2239
|
// src/features/analysis/scm/scmSubmit/types.ts
|
|
2667
|
-
import { z as
|
|
2668
|
-
var BaseSubmitToScmMessageZ =
|
|
2669
|
-
submitFixRequestId:
|
|
2670
|
-
fixes:
|
|
2671
|
-
|
|
2672
|
-
fixId:
|
|
2673
|
-
patches:
|
|
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:
|
|
2677
|
-
repoUrl:
|
|
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
|
-
|
|
2685
|
-
type:
|
|
2686
|
-
branch:
|
|
2687
|
-
commitMessage:
|
|
2688
|
-
commitDescription:
|
|
2689
|
-
githubCommentId:
|
|
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 =
|
|
2693
|
-
type:
|
|
2694
|
-
submitBranch:
|
|
2695
|
-
baseBranch:
|
|
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 =
|
|
2270
|
+
var SubmitFixesMessageZ = z6.union([
|
|
2698
2271
|
CommitToSameBranchParamsZ,
|
|
2699
2272
|
SubmitFixesToDifferentBranchParamsZ
|
|
2700
2273
|
]);
|
|
2701
|
-
var FixResponseArrayZ =
|
|
2702
|
-
|
|
2703
|
-
fixId:
|
|
2274
|
+
var FixResponseArrayZ = z6.array(
|
|
2275
|
+
z6.object({
|
|
2276
|
+
fixId: z6.string().uuid()
|
|
2704
2277
|
})
|
|
2705
2278
|
);
|
|
2706
|
-
var SubmitFixesBaseResponseMessageZ =
|
|
2707
|
-
submitFixRequestId:
|
|
2708
|
-
submitBranches:
|
|
2709
|
-
|
|
2710
|
-
branchName:
|
|
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:
|
|
2715
|
-
type:
|
|
2287
|
+
error: z6.object({
|
|
2288
|
+
type: z6.enum([
|
|
2716
2289
|
"InitialRepoAccessError",
|
|
2717
2290
|
"PushBranchError",
|
|
2718
2291
|
"UnknownError"
|
|
2719
2292
|
]),
|
|
2720
|
-
info:
|
|
2721
|
-
message:
|
|
2722
|
-
pushBranchName:
|
|
2293
|
+
info: z6.object({
|
|
2294
|
+
message: z6.string(),
|
|
2295
|
+
pushBranchName: z6.string().optional()
|
|
2723
2296
|
})
|
|
2724
2297
|
}).optional()
|
|
2725
2298
|
});
|
|
2726
|
-
var SubmitFixesToSameBranchResponseMessageZ =
|
|
2727
|
-
type:
|
|
2728
|
-
githubCommentId:
|
|
2299
|
+
var SubmitFixesToSameBranchResponseMessageZ = z6.object({
|
|
2300
|
+
type: z6.literal(submitToScmMessageType.commitToSameBranch),
|
|
2301
|
+
githubCommentId: z6.number().nullish()
|
|
2729
2302
|
}).merge(SubmitFixesBaseResponseMessageZ);
|
|
2730
|
-
var SubmitFixesToDifferentBranchResponseMessageZ =
|
|
2731
|
-
type:
|
|
2732
|
-
githubCommentId:
|
|
2303
|
+
var SubmitFixesToDifferentBranchResponseMessageZ = z6.object({
|
|
2304
|
+
type: z6.literal(submitToScmMessageType.submitFixesForDifferentBranch),
|
|
2305
|
+
githubCommentId: z6.number().optional()
|
|
2733
2306
|
}).merge(SubmitFixesBaseResponseMessageZ);
|
|
2734
|
-
var SubmitFixesResponseMessageZ =
|
|
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 =
|
|
2741
|
-
BROKERED_HOSTS:
|
|
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 =
|
|
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 =
|
|
2759
|
-
|
|
2760
|
-
fixId:
|
|
2761
|
-
patches:
|
|
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 =
|
|
2767
|
-
date:
|
|
2768
|
-
sha:
|
|
2769
|
-
type:
|
|
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 =
|
|
2383
|
+
const parsedScmLibType = z8.nativeEnum(ScmLibScmType).parse(scmLibType);
|
|
2811
2384
|
return scmLibScmTypeToScmType[parsedScmLibType];
|
|
2812
2385
|
}
|
|
2813
2386
|
function getScmLibTypeFromScmType(scmType) {
|
|
2814
|
-
const parsedScmType =
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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({
|
|
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(
|
|
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 =
|
|
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:
|
|
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(
|
|
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
|
|
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
|
|
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 =
|
|
3844
|
-
status:
|
|
3845
|
-
error:
|
|
3846
|
-
type:
|
|
3847
|
-
error:
|
|
3848
|
-
message:
|
|
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 =
|
|
3854
|
-
access_token:
|
|
3855
|
-
token_type:
|
|
3856
|
-
refresh_token:
|
|
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 =
|
|
3859
|
-
organization:
|
|
3860
|
-
repoName:
|
|
3861
|
-
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) =>
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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) =>
|
|
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
|
-
|
|
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
|
|
4183
|
-
var
|
|
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
|
-
|
|
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/
|
|
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 = ``;
|
|
4233
3787
|
var noVulnerabilitiesFoundTitle = `# ${MobbIconMarkdown} No security issues were found \u2705`;
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
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
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
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
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
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
|
|
4270
|
-
const {
|
|
4271
|
-
|
|
4272
|
-
|
|
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
|
|
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
|
|
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
|
-
} =
|
|
4319
|
-
if (!
|
|
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 } =
|
|
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:
|
|
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 }
|
|
4336
|
-
scm.getGeneralPrComments(
|
|
4337
|
-
{ prNumber: pullRequest },
|
|
4338
|
-
{ authToken: githubActionToken }
|
|
4339
|
-
)
|
|
4089
|
+
scm.getPrComments({ pull_number: pullRequest }),
|
|
4090
|
+
scm.getGeneralPrComments({ prNumber: pullRequest })
|
|
4340
4091
|
]);
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
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
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
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
|
-
|
|
4350
|
-
{
|
|
4351
|
-
body: analysisSummaryComment,
|
|
4352
|
-
prNumber: pullRequest
|
|
4353
|
-
},
|
|
4354
|
-
{ authToken: githubActionToken }
|
|
4355
|
-
);
|
|
4392
|
+
return updateScmTokenResult;
|
|
4356
4393
|
}
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
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
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
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
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
const {
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
if (
|
|
4402
|
-
throw new Error(
|
|
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
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
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
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
}
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
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
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4481
|
+
pullRequest,
|
|
4482
|
+
sha: sha || "",
|
|
4483
|
+
experimentalEnabled,
|
|
4484
|
+
scanSource: params.scanSource
|
|
4435
4485
|
});
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
const
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
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
|
-
|
|
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
|
|
4459
|
-
const
|
|
4460
|
-
|
|
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 (
|
|
4473
|
-
|
|
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
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
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
|
|
4563
|
+
import Debug7 from "debug";
|
|
4543
4564
|
import { globby } from "globby";
|
|
4544
4565
|
import { isBinary } from "istextorbinary";
|
|
4545
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
4585
|
+
debug7("files found %d", filepaths.length);
|
|
4564
4586
|
const zip = new AdmZip();
|
|
4565
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
4708
|
+
debug12(`chunk received from ${name} std ${chunk}`);
|
|
4687
4709
|
out += chunk;
|
|
4688
4710
|
};
|
|
4689
4711
|
if (!childProcess || !childProcess?.stdout || !childProcess?.stderr) {
|
|
4690
|
-
|
|
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
|
-
|
|
4722
|
+
debug12(`${name} exit code ${code}`);
|
|
4701
4723
|
resolve({ message: out, code });
|
|
4702
4724
|
});
|
|
4703
4725
|
childProcess.on("error", (err) => {
|
|
4704
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
4855
|
+
import Debug10 from "debug";
|
|
4834
4856
|
import { createSpinner as createSpinner3 } from "nanospinner";
|
|
4835
4857
|
import open from "open";
|
|
4836
|
-
var
|
|
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
|
-
|
|
4862
|
+
debug9("snyk executable path %s", SNYK_PATH);
|
|
4841
4863
|
async function forkSnyk(args, { display }) {
|
|
4842
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4900
|
+
debug9("answer %s", answer);
|
|
4879
4901
|
if (answer) {
|
|
4880
|
-
|
|
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
|
|
4917
|
+
import Debug11 from "debug";
|
|
4896
4918
|
import fetch2, { File, fileFrom, FormData } from "node-fetch";
|
|
4897
|
-
var
|
|
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
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
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
|
-
|
|
4937
|
+
debug10("upload file from path %s", file);
|
|
4916
4938
|
form.append("file", await fileFrom(file));
|
|
4917
4939
|
} else {
|
|
4918
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4971
|
+
debug11("download repo %s %s %s", repoUrl, dirname);
|
|
4950
4972
|
const zipFilePath = path6.join(dirname, "repo.zip");
|
|
4951
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
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
|
-
|
|
5282
|
+
debug11("encrypted API token received %s", encryptedApiToken);
|
|
5276
5283
|
newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
|
|
5277
|
-
|
|
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
|
-
|
|
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
|
}
|