mobbdev 0.0.148 → 0.0.155
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 +1643 -1513
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -32,663 +32,174 @@ import fs4 from "node:fs";
|
|
|
32
32
|
import path7 from "node:path";
|
|
33
33
|
|
|
34
34
|
// src/constants.ts
|
|
35
|
-
import
|
|
35
|
+
import path2 from "node:path";
|
|
36
36
|
import { fileURLToPath } from "node:url";
|
|
37
37
|
import chalk from "chalk";
|
|
38
38
|
import Debug from "debug";
|
|
39
39
|
import * as dotenv from "dotenv";
|
|
40
|
-
import { z } from "zod";
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
49
|
-
var SCANNERS = {
|
|
50
|
-
Checkmarx: "checkmarx",
|
|
51
|
-
Codeql: "codeql",
|
|
52
|
-
Fortify: "fortify",
|
|
53
|
-
Snyk: "snyk",
|
|
54
|
-
Sonarqube: "sonarqube"
|
|
55
|
-
};
|
|
56
|
-
var SupportedScannersZ = z.enum([SCANNERS.Checkmarx, SCANNERS.Snyk]);
|
|
57
|
-
var envVariablesSchema = z.object({
|
|
58
|
-
WEB_APP_URL: z.string(),
|
|
59
|
-
API_URL: z.string(),
|
|
60
|
-
HASURA_ACCESS_KEY: z.string(),
|
|
61
|
-
LOCAL_GRAPHQL_ENDPOINT: z.string()
|
|
62
|
-
}).required();
|
|
63
|
-
var envVariables = envVariablesSchema.parse(process.env);
|
|
64
|
-
debug("config %o", envVariables);
|
|
65
|
-
var mobbAscii = `
|
|
66
|
-
..
|
|
67
|
-
..........
|
|
68
|
-
.................
|
|
69
|
-
...........................
|
|
70
|
-
..............................
|
|
71
|
-
................................
|
|
72
|
-
..................................
|
|
73
|
-
....................................
|
|
74
|
-
.....................................
|
|
75
|
-
.............................................
|
|
76
|
-
.................................................
|
|
77
|
-
............................... .................
|
|
78
|
-
.................................. ............
|
|
79
|
-
.................. ............. ..........
|
|
80
|
-
......... ........ ......... ......
|
|
81
|
-
............... ....
|
|
82
|
-
.... ..
|
|
83
|
-
|
|
84
|
-
. ...
|
|
85
|
-
..............
|
|
86
|
-
......................
|
|
87
|
-
...........................
|
|
88
|
-
................................
|
|
89
|
-
......................................
|
|
90
|
-
...............................
|
|
91
|
-
.................
|
|
92
|
-
`;
|
|
93
|
-
var PROJECT_DEFAULT_NAME = "My first project";
|
|
94
|
-
var WEB_APP_URL = envVariables.WEB_APP_URL;
|
|
95
|
-
var API_URL = envVariables.API_URL;
|
|
96
|
-
var HASURA_ACCESS_KEY = envVariables.HASURA_ACCESS_KEY;
|
|
97
|
-
var LOCAL_GRAPHQL_ENDPOINT = envVariables.LOCAL_GRAPHQL_ENDPOINT;
|
|
98
|
-
var errorMessages = {
|
|
99
|
-
missingCxProjectName: `project name ${chalk.bold(
|
|
100
|
-
"(--cx-project-name)"
|
|
101
|
-
)} is needed if you're using checkmarx`,
|
|
102
|
-
missingUrl: `url ${chalk.bold(
|
|
103
|
-
"(--url)"
|
|
104
|
-
)} is needed if you're adding an SCM token`,
|
|
105
|
-
invalidScmType: `SCM type ${chalk.bold(
|
|
106
|
-
"(--scm-type)"
|
|
107
|
-
)} is invalid, please use one of: ${Object.values(ScmTypes).join(", ")}`,
|
|
108
|
-
missingToken: `SCM token ${chalk.bold(
|
|
109
|
-
"(--token)"
|
|
110
|
-
)} is needed if you're adding an SCM token`
|
|
111
|
-
};
|
|
112
|
-
var progressMassages = {
|
|
113
|
-
processingVulnerabilityReportSuccess: "\u2699\uFE0F Vulnerability report proccessed successfully",
|
|
114
|
-
processingVulnerabilityReport: "\u2699\uFE0F Proccessing vulnerability report",
|
|
115
|
-
processingVulnerabilityReportFailed: "\u2699\uFE0F Error Proccessing vulnerability report"
|
|
40
|
+
import { z as z10 } from "zod";
|
|
41
|
+
|
|
42
|
+
// src/features/analysis/scm/shared/src/types.ts
|
|
43
|
+
var scmCloudUrl = {
|
|
44
|
+
GitLab: "https://gitlab.com",
|
|
45
|
+
GitHub: "https://github.com",
|
|
46
|
+
Ado: "https://dev.azure.com",
|
|
47
|
+
Bitbucket: "https://bitbucket.org"
|
|
116
48
|
};
|
|
117
|
-
var
|
|
49
|
+
var ScmType = /* @__PURE__ */ ((ScmType2) => {
|
|
50
|
+
ScmType2["GitHub"] = "GitHub";
|
|
51
|
+
ScmType2["GitLab"] = "GitLab";
|
|
52
|
+
ScmType2["Ado"] = "Ado";
|
|
53
|
+
ScmType2["Bitbucket"] = "Bitbucket";
|
|
54
|
+
return ScmType2;
|
|
55
|
+
})(ScmType || {});
|
|
118
56
|
|
|
119
|
-
// src/features/analysis/
|
|
120
|
-
|
|
121
|
-
import fs3 from "node:fs";
|
|
122
|
-
import os from "node:os";
|
|
123
|
-
import path6 from "node:path";
|
|
124
|
-
import { pipeline } from "node:stream/promises";
|
|
57
|
+
// src/features/analysis/scm/ado/constants.ts
|
|
58
|
+
var DEFUALT_ADO_ORIGIN = scmCloudUrl.Ado;
|
|
125
59
|
|
|
126
|
-
// src/
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
60
|
+
// src/features/analysis/scm/ado/utils.ts
|
|
61
|
+
import querystring3 from "node:querystring";
|
|
62
|
+
import * as api from "azure-devops-node-api";
|
|
63
|
+
import { z as z9 } from "zod";
|
|
64
|
+
|
|
65
|
+
// src/features/analysis/scm/env.ts
|
|
66
|
+
import { z } from "zod";
|
|
67
|
+
var EnvVariablesZod = z.object({
|
|
68
|
+
GITLAB_API_TOKEN: z.string().optional(),
|
|
69
|
+
BROKERED_HOSTS: z.string().toLowerCase().transform(
|
|
70
|
+
(x) => x.split(",").map((url) => url.trim(), []).filter(Boolean)
|
|
71
|
+
).default(""),
|
|
72
|
+
GITHUB_API_TOKEN: z.string().optional(),
|
|
73
|
+
GIT_PROXY_HOST: z.string().default("http://tinyproxy:8888")
|
|
74
|
+
});
|
|
75
|
+
var { GITLAB_API_TOKEN, BROKERED_HOSTS, GITHUB_API_TOKEN, GIT_PROXY_HOST } = EnvVariablesZod.parse(process.env);
|
|
76
|
+
|
|
77
|
+
// src/features/analysis/scm/scm.ts
|
|
78
|
+
import { z as z7 } from "zod";
|
|
79
|
+
|
|
80
|
+
// src/features/analysis/scm/bitbucket/bitbucket.ts
|
|
81
|
+
import querystring from "node:querystring";
|
|
82
|
+
import bitbucketPkg from "bitbucket";
|
|
83
|
+
import * as bitbucketPkgNode from "bitbucket";
|
|
84
|
+
import { z as z3 } from "zod";
|
|
85
|
+
|
|
86
|
+
// src/features/analysis/scm/shared/src/urlParser/urlParser.ts
|
|
87
|
+
import { z as z2 } from "zod";
|
|
88
|
+
function detectAdoUrl(args) {
|
|
89
|
+
const { pathname, hostname, scmType } = args;
|
|
90
|
+
const hostnameParts = hostname.split(".");
|
|
91
|
+
const adoCloudHostname = new URL(scmCloudUrl.Ado).hostname;
|
|
92
|
+
const prefixPath = pathname.at(0)?.toLowerCase() === ADO_PREFIX_PATH ? ADO_PREFIX_PATH : "";
|
|
93
|
+
const normilizedPath = prefixPath ? pathname.slice(1) : pathname;
|
|
94
|
+
if (hostnameParts.length === 3 && hostnameParts[1] === "visualstudio" && hostnameParts[2] === "com") {
|
|
95
|
+
if (normilizedPath.length === 2 && normilizedPath[0] === "_git") {
|
|
96
|
+
const [_git, projectName] = normilizedPath;
|
|
97
|
+
const [organization] = hostnameParts;
|
|
98
|
+
return {
|
|
99
|
+
scmType: "Ado" /* Ado */,
|
|
100
|
+
organization,
|
|
101
|
+
// project has single repo - repoName === projectName
|
|
102
|
+
projectName: z2.string().parse(projectName),
|
|
103
|
+
repoName: projectName,
|
|
104
|
+
prefixPath
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (normilizedPath.length === 3 && normilizedPath[1] === "_git") {
|
|
108
|
+
const [projectName, _git, repoName] = normilizedPath;
|
|
109
|
+
const [organization] = hostnameParts;
|
|
110
|
+
return {
|
|
111
|
+
scmType: "Ado" /* Ado */,
|
|
112
|
+
organization,
|
|
113
|
+
projectName: z2.string().parse(projectName),
|
|
114
|
+
repoName,
|
|
115
|
+
prefixPath
|
|
116
|
+
};
|
|
144
117
|
}
|
|
145
118
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
119
|
+
if (hostname === adoCloudHostname || scmType === "Ado" /* Ado */) {
|
|
120
|
+
if (normilizedPath[normilizedPath.length - 2] === "_git") {
|
|
121
|
+
if (normilizedPath.length === 3) {
|
|
122
|
+
const [organization, _git, repoName] = normilizedPath;
|
|
123
|
+
return {
|
|
124
|
+
scmType: "Ado" /* Ado */,
|
|
125
|
+
organization,
|
|
126
|
+
// project has only one repo - repoName === projectName
|
|
127
|
+
projectName: z2.string().parse(repoName),
|
|
128
|
+
repoName,
|
|
129
|
+
prefixPath
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (normilizedPath.length === 4) {
|
|
133
|
+
const [organization, projectName, _git, repoName] = normilizedPath;
|
|
134
|
+
return {
|
|
135
|
+
scmType: "Ado" /* Ado */,
|
|
136
|
+
organization,
|
|
137
|
+
projectName: z2.string().parse(projectName),
|
|
138
|
+
repoName,
|
|
139
|
+
prefixPath
|
|
140
|
+
};
|
|
160
141
|
}
|
|
161
142
|
}
|
|
162
143
|
}
|
|
144
|
+
return null;
|
|
163
145
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
state
|
|
146
|
+
function detectGithubUrl(args) {
|
|
147
|
+
const { pathname, hostname, scmType } = args;
|
|
148
|
+
const githubHostname = new URL(scmCloudUrl.GitHub).hostname;
|
|
149
|
+
if (hostname === githubHostname || scmType === "GitHub" /* GitHub */) {
|
|
150
|
+
if (pathname.length === 2) {
|
|
151
|
+
return {
|
|
152
|
+
scmType: "GitHub" /* GitHub */,
|
|
153
|
+
organization: pathname[0],
|
|
154
|
+
repoName: pathname[1]
|
|
155
|
+
};
|
|
156
|
+
}
|
|
176
157
|
}
|
|
158
|
+
return null;
|
|
177
159
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
160
|
+
function detectGitlabUrl(args) {
|
|
161
|
+
const { pathname, hostname, scmType } = args;
|
|
162
|
+
const gitlabHostname = new URL(scmCloudUrl.GitLab).hostname;
|
|
163
|
+
if (hostname === gitlabHostname || scmType === "GitLab" /* GitLab */) {
|
|
164
|
+
if (pathname.length >= 2) {
|
|
165
|
+
return {
|
|
166
|
+
scmType: "GitLab" /* GitLab */,
|
|
167
|
+
organization: pathname[0],
|
|
168
|
+
repoName: pathname[pathname.length - 1]
|
|
169
|
+
};
|
|
170
|
+
}
|
|
185
171
|
}
|
|
172
|
+
return null;
|
|
186
173
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
174
|
+
function detectBitbucketUrl(args) {
|
|
175
|
+
const { pathname, hostname, scmType } = args;
|
|
176
|
+
const bitbucketHostname = new URL(scmCloudUrl.Bitbucket).hostname;
|
|
177
|
+
if (hostname === bitbucketHostname || scmType === "Bitbucket" /* Bitbucket */) {
|
|
178
|
+
if (pathname.length === 2) {
|
|
179
|
+
return {
|
|
180
|
+
scmType: "Bitbucket" /* Bitbucket */,
|
|
181
|
+
organization: pathname[0],
|
|
182
|
+
repoName: pathname[1]
|
|
183
|
+
};
|
|
184
|
+
}
|
|
193
185
|
}
|
|
186
|
+
return null;
|
|
194
187
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
vulnerabilityReport {
|
|
207
|
-
projectId
|
|
208
|
-
project {
|
|
209
|
-
organizationId
|
|
210
|
-
}
|
|
211
|
-
file {
|
|
212
|
-
signedFile {
|
|
213
|
-
url
|
|
214
|
-
}
|
|
215
|
-
}
|
|
188
|
+
var getRepoUrlFunctionMap = {
|
|
189
|
+
["GitLab" /* GitLab */]: detectGitlabUrl,
|
|
190
|
+
["GitHub" /* GitHub */]: detectGithubUrl,
|
|
191
|
+
["Ado" /* Ado */]: detectAdoUrl,
|
|
192
|
+
["Bitbucket" /* Bitbucket */]: detectBitbucketUrl
|
|
193
|
+
};
|
|
194
|
+
function getRepoInfo(args) {
|
|
195
|
+
for (const detectUrl of Object.values(getRepoUrlFunctionMap)) {
|
|
196
|
+
const detectUrlRes = detectUrl(args);
|
|
197
|
+
if (detectUrlRes) {
|
|
198
|
+
return detectUrlRes;
|
|
216
199
|
}
|
|
217
200
|
}
|
|
201
|
+
return null;
|
|
218
202
|
}
|
|
219
|
-
`;
|
|
220
|
-
var GetFixesDocument = `
|
|
221
|
-
query getFixes($filters: fix_bool_exp!) {
|
|
222
|
-
fixes: fix(where: $filters) {
|
|
223
|
-
issueType
|
|
224
|
-
id
|
|
225
|
-
patchAndQuestions {
|
|
226
|
-
__typename
|
|
227
|
-
... on FixData {
|
|
228
|
-
patch
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
`;
|
|
234
|
-
var GetVulByNodesMetadataDocument = `
|
|
235
|
-
query getVulByNodesMetadata($filters: [vulnerability_report_issue_code_node_bool_exp!], $vulnerabilityReportId: uuid!) {
|
|
236
|
-
vulnerabilityReportIssueCodeNodes: vulnerability_report_issue_code_node(
|
|
237
|
-
order_by: {index: desc}
|
|
238
|
-
where: {_or: $filters, vulnerabilityReportIssue: {fixId: {_is_null: false}, vulnerabilityReportId: {_eq: $vulnerabilityReportId}}}
|
|
239
|
-
) {
|
|
240
|
-
vulnerabilityReportIssueId
|
|
241
|
-
path
|
|
242
|
-
startLine
|
|
243
|
-
vulnerabilityReportIssue {
|
|
244
|
-
issueType
|
|
245
|
-
fixId
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
fixablePrVuls: vulnerability_report_issue_aggregate(
|
|
249
|
-
where: {fixId: {_is_null: false}, vulnerabilityReportId: {_eq: $vulnerabilityReportId}, codeNodes: {_or: $filters}}
|
|
250
|
-
) {
|
|
251
|
-
aggregate {
|
|
252
|
-
count
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
nonFixablePrVuls: vulnerability_report_issue_aggregate(
|
|
256
|
-
where: {fixId: {_is_null: true}, vulnerabilityReportId: {_eq: $vulnerabilityReportId}, codeNodes: {_or: $filters}}
|
|
257
|
-
) {
|
|
258
|
-
aggregate {
|
|
259
|
-
count
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
totalScanVulnerabilities: vulnerability_report_issue_aggregate(
|
|
263
|
-
where: {vulnerabilityReportId: {_eq: $vulnerabilityReportId}}
|
|
264
|
-
) {
|
|
265
|
-
aggregate {
|
|
266
|
-
count
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
`;
|
|
271
|
-
var UpdateScmTokenDocument = `
|
|
272
|
-
mutation updateScmToken($scmType: String!, $url: String!, $token: String!, $org: String, $refreshToken: String) {
|
|
273
|
-
updateScmToken(
|
|
274
|
-
scmType: $scmType
|
|
275
|
-
url: $url
|
|
276
|
-
token: $token
|
|
277
|
-
org: $org
|
|
278
|
-
refreshToken: $refreshToken
|
|
279
|
-
) {
|
|
280
|
-
__typename
|
|
281
|
-
... on ScmAccessTokenUpdateSuccess {
|
|
282
|
-
token
|
|
283
|
-
}
|
|
284
|
-
... on InvalidScmTypeError {
|
|
285
|
-
status
|
|
286
|
-
error
|
|
287
|
-
}
|
|
288
|
-
... on BadScmCredentials {
|
|
289
|
-
status
|
|
290
|
-
error
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
`;
|
|
295
|
-
var UploadS3BucketInfoDocument = `
|
|
296
|
-
mutation uploadS3BucketInfo($fileName: String!) {
|
|
297
|
-
uploadS3BucketInfo(fileName: $fileName) {
|
|
298
|
-
status
|
|
299
|
-
error
|
|
300
|
-
reportUploadInfo: uploadInfo {
|
|
301
|
-
url
|
|
302
|
-
fixReportId
|
|
303
|
-
uploadFieldsJSON
|
|
304
|
-
uploadKey
|
|
305
|
-
}
|
|
306
|
-
repoUploadInfo {
|
|
307
|
-
url
|
|
308
|
-
fixReportId
|
|
309
|
-
uploadFieldsJSON
|
|
310
|
-
uploadKey
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
`;
|
|
315
|
-
var DigestVulnerabilityReportDocument = `
|
|
316
|
-
mutation DigestVulnerabilityReport($vulnerabilityReportFileName: String!, $fixReportId: String!, $projectId: String!, $scanSource: String!) {
|
|
317
|
-
digestVulnerabilityReport(
|
|
318
|
-
fixReportId: $fixReportId
|
|
319
|
-
vulnerabilityReportFileName: $vulnerabilityReportFileName
|
|
320
|
-
projectId: $projectId
|
|
321
|
-
scanSource: $scanSource
|
|
322
|
-
) {
|
|
323
|
-
__typename
|
|
324
|
-
... on VulnerabilityReport {
|
|
325
|
-
vulnerabilityReportId
|
|
326
|
-
fixReportId
|
|
327
|
-
}
|
|
328
|
-
... on RabbitSendError {
|
|
329
|
-
status
|
|
330
|
-
error
|
|
331
|
-
}
|
|
332
|
-
... on ReportValidationError {
|
|
333
|
-
status
|
|
334
|
-
error
|
|
335
|
-
}
|
|
336
|
-
... on ReferenceNotFoundError {
|
|
337
|
-
status
|
|
338
|
-
error
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
`;
|
|
343
|
-
var SubmitVulnerabilityReportDocument = `
|
|
344
|
-
mutation SubmitVulnerabilityReport($fixReportId: String!, $repoUrl: String!, $reference: String!, $projectId: String!, $scanSource: String!, $sha: String, $experimentalEnabled: Boolean, $vulnerabilityReportFileName: String, $pullRequest: Int) {
|
|
345
|
-
submitVulnerabilityReport(
|
|
346
|
-
fixReportId: $fixReportId
|
|
347
|
-
repoUrl: $repoUrl
|
|
348
|
-
reference: $reference
|
|
349
|
-
sha: $sha
|
|
350
|
-
experimentalEnabled: $experimentalEnabled
|
|
351
|
-
pullRequest: $pullRequest
|
|
352
|
-
projectId: $projectId
|
|
353
|
-
vulnerabilityReportFileName: $vulnerabilityReportFileName
|
|
354
|
-
scanSource: $scanSource
|
|
355
|
-
) {
|
|
356
|
-
__typename
|
|
357
|
-
... on VulnerabilityReport {
|
|
358
|
-
vulnerabilityReportId
|
|
359
|
-
fixReportId
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
`;
|
|
364
|
-
var CreateCommunityUserDocument = `
|
|
365
|
-
mutation CreateCommunityUser {
|
|
366
|
-
initOrganizationAndProject {
|
|
367
|
-
__typename
|
|
368
|
-
... on InitOrganizationAndProjectGoodResponse {
|
|
369
|
-
projectId
|
|
370
|
-
userId
|
|
371
|
-
organizationId
|
|
372
|
-
}
|
|
373
|
-
... on UserAlreadyInProjectError {
|
|
374
|
-
error
|
|
375
|
-
status
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
`;
|
|
380
|
-
var CreateCliLoginDocument = `
|
|
381
|
-
mutation CreateCliLogin($publicKey: String!) {
|
|
382
|
-
insert_cli_login_one(object: {publicKey: $publicKey}) {
|
|
383
|
-
id
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
`;
|
|
387
|
-
var PerformCliLoginDocument = `
|
|
388
|
-
mutation performCliLogin($loginId: String!) {
|
|
389
|
-
performCliLogin(loginId: $loginId) {
|
|
390
|
-
status
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
`;
|
|
394
|
-
var CreateProjectDocument = `
|
|
395
|
-
mutation CreateProject($organizationId: String!, $projectName: String!) {
|
|
396
|
-
createProject(organizationId: $organizationId, projectName: $projectName) {
|
|
397
|
-
projectId
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
`;
|
|
401
|
-
var defaultWrapper = (action, _operationName, _operationType, _variables) => action();
|
|
402
|
-
function getSdk(client, withWrapper = defaultWrapper) {
|
|
403
|
-
return {
|
|
404
|
-
Me(variables, requestHeaders) {
|
|
405
|
-
return withWrapper((wrappedRequestHeaders) => client.request(MeDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "Me", "query", variables);
|
|
406
|
-
},
|
|
407
|
-
getOrgAndProjectId(variables, requestHeaders) {
|
|
408
|
-
return withWrapper((wrappedRequestHeaders) => client.request(GetOrgAndProjectIdDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getOrgAndProjectId", "query", variables);
|
|
409
|
-
},
|
|
410
|
-
GetEncryptedApiToken(variables, requestHeaders) {
|
|
411
|
-
return withWrapper((wrappedRequestHeaders) => client.request(GetEncryptedApiTokenDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "GetEncryptedApiToken", "query", variables);
|
|
412
|
-
},
|
|
413
|
-
FixReportState(variables, requestHeaders) {
|
|
414
|
-
return withWrapper((wrappedRequestHeaders) => client.request(FixReportStateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "FixReportState", "query", variables);
|
|
415
|
-
},
|
|
416
|
-
GetVulnerabilityReportPaths(variables, requestHeaders) {
|
|
417
|
-
return withWrapper((wrappedRequestHeaders) => client.request(GetVulnerabilityReportPathsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "GetVulnerabilityReportPaths", "query", variables);
|
|
418
|
-
},
|
|
419
|
-
getAnalysis(variables, requestHeaders) {
|
|
420
|
-
return withWrapper((wrappedRequestHeaders) => client.request(GetAnalysisDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getAnalysis", "subscription", variables);
|
|
421
|
-
},
|
|
422
|
-
getAnalsyis(variables, requestHeaders) {
|
|
423
|
-
return withWrapper((wrappedRequestHeaders) => client.request(GetAnalsyisDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getAnalsyis", "query", variables);
|
|
424
|
-
},
|
|
425
|
-
getFixes(variables, requestHeaders) {
|
|
426
|
-
return withWrapper((wrappedRequestHeaders) => client.request(GetFixesDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getFixes", "query", variables);
|
|
427
|
-
},
|
|
428
|
-
getVulByNodesMetadata(variables, requestHeaders) {
|
|
429
|
-
return withWrapper((wrappedRequestHeaders) => client.request(GetVulByNodesMetadataDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getVulByNodesMetadata", "query", variables);
|
|
430
|
-
},
|
|
431
|
-
updateScmToken(variables, requestHeaders) {
|
|
432
|
-
return withWrapper((wrappedRequestHeaders) => client.request(UpdateScmTokenDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "updateScmToken", "mutation", variables);
|
|
433
|
-
},
|
|
434
|
-
uploadS3BucketInfo(variables, requestHeaders) {
|
|
435
|
-
return withWrapper((wrappedRequestHeaders) => client.request(UploadS3BucketInfoDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "uploadS3BucketInfo", "mutation", variables);
|
|
436
|
-
},
|
|
437
|
-
DigestVulnerabilityReport(variables, requestHeaders) {
|
|
438
|
-
return withWrapper((wrappedRequestHeaders) => client.request(DigestVulnerabilityReportDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "DigestVulnerabilityReport", "mutation", variables);
|
|
439
|
-
},
|
|
440
|
-
SubmitVulnerabilityReport(variables, requestHeaders) {
|
|
441
|
-
return withWrapper((wrappedRequestHeaders) => client.request(SubmitVulnerabilityReportDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SubmitVulnerabilityReport", "mutation", variables);
|
|
442
|
-
},
|
|
443
|
-
CreateCommunityUser(variables, requestHeaders) {
|
|
444
|
-
return withWrapper((wrappedRequestHeaders) => client.request(CreateCommunityUserDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CreateCommunityUser", "mutation", variables);
|
|
445
|
-
},
|
|
446
|
-
CreateCliLogin(variables, requestHeaders) {
|
|
447
|
-
return withWrapper((wrappedRequestHeaders) => client.request(CreateCliLoginDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CreateCliLogin", "mutation", variables);
|
|
448
|
-
},
|
|
449
|
-
performCliLogin(variables, requestHeaders) {
|
|
450
|
-
return withWrapper((wrappedRequestHeaders) => client.request(PerformCliLoginDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "performCliLogin", "mutation", variables);
|
|
451
|
-
},
|
|
452
|
-
CreateProject(variables, requestHeaders) {
|
|
453
|
-
return withWrapper((wrappedRequestHeaders) => client.request(CreateProjectDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CreateProject", "mutation", variables);
|
|
454
|
-
}
|
|
455
|
-
};
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// src/utils/index.ts
|
|
459
|
-
var utils_exports = {};
|
|
460
|
-
__export(utils_exports, {
|
|
461
|
-
CliError: () => CliError,
|
|
462
|
-
Spinner: () => Spinner,
|
|
463
|
-
getDirName: () => getDirName,
|
|
464
|
-
getTopLevelDirName: () => getTopLevelDirName,
|
|
465
|
-
keypress: () => keypress,
|
|
466
|
-
sleep: () => sleep
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
// src/utils/dirname.ts
|
|
470
|
-
import path2 from "node:path";
|
|
471
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
472
|
-
function getDirName() {
|
|
473
|
-
return path2.dirname(fileURLToPath2(import.meta.url));
|
|
474
|
-
}
|
|
475
|
-
function getTopLevelDirName(fullPath) {
|
|
476
|
-
return path2.parse(fullPath).name;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// src/utils/keypress.ts
|
|
480
|
-
import readline from "node:readline";
|
|
481
|
-
async function keypress() {
|
|
482
|
-
const rl = readline.createInterface({
|
|
483
|
-
input: process.stdin,
|
|
484
|
-
output: process.stdout
|
|
485
|
-
});
|
|
486
|
-
return new Promise((resolve) => {
|
|
487
|
-
rl.question("", (answer) => {
|
|
488
|
-
rl.close();
|
|
489
|
-
process.stderr.moveCursor(0, -1);
|
|
490
|
-
process.stderr.clearLine(1);
|
|
491
|
-
resolve(answer);
|
|
492
|
-
});
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// src/utils/spinner.ts
|
|
497
|
-
import {
|
|
498
|
-
createSpinner as _createSpinner
|
|
499
|
-
} from "nanospinner";
|
|
500
|
-
var mockSpinner = {
|
|
501
|
-
success: () => mockSpinner,
|
|
502
|
-
error: () => mockSpinner,
|
|
503
|
-
warn: () => mockSpinner,
|
|
504
|
-
stop: () => mockSpinner,
|
|
505
|
-
start: () => mockSpinner,
|
|
506
|
-
update: () => mockSpinner,
|
|
507
|
-
reset: () => mockSpinner,
|
|
508
|
-
clear: () => mockSpinner,
|
|
509
|
-
spin: () => mockSpinner
|
|
510
|
-
};
|
|
511
|
-
function Spinner({ ci = false } = {}) {
|
|
512
|
-
return {
|
|
513
|
-
createSpinner: (text, options) => ci ? mockSpinner : _createSpinner(text, options)
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
// src/utils/index.ts
|
|
518
|
-
var sleep = (ms = 2e3) => new Promise((r) => setTimeout(r, ms));
|
|
519
|
-
var CliError = class extends Error {
|
|
520
|
-
};
|
|
521
|
-
|
|
522
|
-
// src/features/analysis/index.ts
|
|
523
|
-
import chalk4 from "chalk";
|
|
524
|
-
import Configstore from "configstore";
|
|
525
|
-
import Debug12 from "debug";
|
|
526
|
-
import extract from "extract-zip";
|
|
527
|
-
import fetch4 from "node-fetch";
|
|
528
|
-
import open2 from "open";
|
|
529
|
-
import semver from "semver";
|
|
530
|
-
import tmp2 from "tmp";
|
|
531
|
-
import { z as z12 } from "zod";
|
|
532
|
-
|
|
533
|
-
// src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
|
|
534
|
-
import Debug4 from "debug";
|
|
535
|
-
|
|
536
|
-
// src/features/analysis/scm/types.ts
|
|
537
|
-
var ReferenceType = /* @__PURE__ */ ((ReferenceType2) => {
|
|
538
|
-
ReferenceType2["BRANCH"] = "BRANCH";
|
|
539
|
-
ReferenceType2["COMMIT"] = "COMMIT";
|
|
540
|
-
ReferenceType2["TAG"] = "TAG";
|
|
541
|
-
return ReferenceType2;
|
|
542
|
-
})(ReferenceType || {});
|
|
543
|
-
var ScmLibScmType = /* @__PURE__ */ ((ScmLibScmType2) => {
|
|
544
|
-
ScmLibScmType2["GITHUB"] = "GITHUB";
|
|
545
|
-
ScmLibScmType2["GITLAB"] = "GITLAB";
|
|
546
|
-
ScmLibScmType2["ADO"] = "ADO";
|
|
547
|
-
ScmLibScmType2["BITBUCKET"] = "BITBUCKET";
|
|
548
|
-
return ScmLibScmType2;
|
|
549
|
-
})(ScmLibScmType || {});
|
|
550
|
-
var scmCloudUrl = {
|
|
551
|
-
GitLab: "https://gitlab.com",
|
|
552
|
-
GitHub: "https://github.com",
|
|
553
|
-
Ado: "https://dev.azure.com",
|
|
554
|
-
Bitbucket: "https://bitbucket.org"
|
|
555
|
-
};
|
|
556
|
-
var ScmType = /* @__PURE__ */ ((ScmType2) => {
|
|
557
|
-
ScmType2["GitHub"] = "GitHub";
|
|
558
|
-
ScmType2["GitLab"] = "GitLab";
|
|
559
|
-
ScmType2["Ado"] = "Ado";
|
|
560
|
-
ScmType2["Bitbucket"] = "Bitbucket";
|
|
561
|
-
return ScmType2;
|
|
562
|
-
})(ScmType || {});
|
|
563
|
-
|
|
564
|
-
// src/features/analysis/scm/ado/constants.ts
|
|
565
|
-
var DEFUALT_ADO_ORIGIN = scmCloudUrl.Ado;
|
|
566
|
-
|
|
567
|
-
// src/features/analysis/scm/ado/utils.ts
|
|
568
|
-
import querystring3 from "node:querystring";
|
|
569
|
-
import * as api from "azure-devops-node-api";
|
|
570
|
-
import { z as z9 } from "zod";
|
|
571
|
-
|
|
572
|
-
// src/features/analysis/scm/env.ts
|
|
573
|
-
import { z as z2 } from "zod";
|
|
574
|
-
var EnvVariablesZod = z2.object({
|
|
575
|
-
GITLAB_API_TOKEN: z2.string().optional(),
|
|
576
|
-
BROKERED_HOSTS: z2.string().toLowerCase().transform(
|
|
577
|
-
(x) => x.split(",").map((url) => url.trim(), []).filter(Boolean)
|
|
578
|
-
).default(""),
|
|
579
|
-
GITHUB_API_TOKEN: z2.string().optional(),
|
|
580
|
-
GIT_PROXY_HOST: z2.string().default("http://tinyproxy:8888")
|
|
581
|
-
});
|
|
582
|
-
var { GITLAB_API_TOKEN, BROKERED_HOSTS, GITHUB_API_TOKEN, GIT_PROXY_HOST } = EnvVariablesZod.parse(process.env);
|
|
583
|
-
|
|
584
|
-
// src/features/analysis/scm/scm.ts
|
|
585
|
-
import { z as z7 } from "zod";
|
|
586
|
-
|
|
587
|
-
// src/features/analysis/scm/bitbucket/bitbucket.ts
|
|
588
|
-
import querystring from "node:querystring";
|
|
589
|
-
import bitbucketPkg from "bitbucket";
|
|
590
|
-
import * as bitbucketPkgNode from "bitbucket";
|
|
591
|
-
import { z as z3 } from "zod";
|
|
592
|
-
|
|
593
|
-
// src/features/analysis/scm/urlParser.ts
|
|
594
|
-
function detectAdoUrl(args) {
|
|
595
|
-
const { pathname, hostname, scmType } = args;
|
|
596
|
-
const hostnameParts = hostname.split(".");
|
|
597
|
-
const adoHostname = new URL(scmCloudUrl.Ado).hostname;
|
|
598
|
-
if (hostnameParts.length === 3 && hostnameParts[1] === "visualstudio" && hostnameParts[2] === "com") {
|
|
599
|
-
if (pathname.length === 2 && pathname[0] === "_git") {
|
|
600
|
-
return {
|
|
601
|
-
organization: hostnameParts[0],
|
|
602
|
-
projectName: pathname[1],
|
|
603
|
-
repoName: pathname[1]
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
if (pathname.length === 3 && pathname[1] === "_git") {
|
|
607
|
-
return {
|
|
608
|
-
organization: hostnameParts[0],
|
|
609
|
-
projectName: pathname[0],
|
|
610
|
-
repoName: pathname[2]
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
if (hostname === adoHostname || scmType === "Ado" /* Ado */) {
|
|
615
|
-
if (pathname[pathname.length - 2] === "_git") {
|
|
616
|
-
if (pathname.length === 3) {
|
|
617
|
-
return {
|
|
618
|
-
organization: pathname[0],
|
|
619
|
-
projectName: pathname[2],
|
|
620
|
-
repoName: pathname[2]
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
if (pathname.length > 3) {
|
|
624
|
-
return {
|
|
625
|
-
organization: pathname[pathname.length - 4],
|
|
626
|
-
projectName: pathname[pathname.length - 3],
|
|
627
|
-
repoName: pathname[pathname.length - 1]
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
return null;
|
|
633
|
-
}
|
|
634
|
-
function detectGithubUrl(args) {
|
|
635
|
-
const { pathname, hostname, scmType } = args;
|
|
636
|
-
const githubHostname = new URL(scmCloudUrl.GitHub).hostname;
|
|
637
|
-
if (hostname === githubHostname || scmType === "GitHub" /* GitHub */) {
|
|
638
|
-
if (pathname.length === 2) {
|
|
639
|
-
return {
|
|
640
|
-
organization: pathname[0],
|
|
641
|
-
projectName: void 0,
|
|
642
|
-
repoName: pathname[1]
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
return null;
|
|
647
|
-
}
|
|
648
|
-
function detectGitlabUrl(args) {
|
|
649
|
-
const { pathname, hostname, scmType } = args;
|
|
650
|
-
const gitlabHostname = new URL(scmCloudUrl.GitLab).hostname;
|
|
651
|
-
if (hostname === gitlabHostname || scmType === "GitLab" /* GitLab */) {
|
|
652
|
-
if (pathname.length >= 2) {
|
|
653
|
-
return {
|
|
654
|
-
organization: pathname[0],
|
|
655
|
-
projectName: void 0,
|
|
656
|
-
repoName: pathname[pathname.length - 1]
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
return null;
|
|
661
|
-
}
|
|
662
|
-
function detectBitbucketUrl(args) {
|
|
663
|
-
const { pathname, hostname, scmType } = args;
|
|
664
|
-
const bitbucketHostname = new URL(scmCloudUrl.Bitbucket).hostname;
|
|
665
|
-
if (hostname === bitbucketHostname || scmType === "Bitbucket" /* Bitbucket */) {
|
|
666
|
-
if (pathname.length === 2) {
|
|
667
|
-
return {
|
|
668
|
-
organization: pathname[0],
|
|
669
|
-
projectName: void 0,
|
|
670
|
-
repoName: pathname[1]
|
|
671
|
-
};
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
return null;
|
|
675
|
-
}
|
|
676
|
-
var getRepoUrlFunctionMap = {
|
|
677
|
-
["GitLab" /* GitLab */]: detectGitlabUrl,
|
|
678
|
-
["GitHub" /* GitHub */]: detectGithubUrl,
|
|
679
|
-
["Ado" /* Ado */]: detectAdoUrl,
|
|
680
|
-
["Bitbucket" /* Bitbucket */]: detectBitbucketUrl
|
|
681
|
-
};
|
|
682
|
-
function getRepoInfo(args) {
|
|
683
|
-
for (const detectUrl of Object.values(getRepoUrlFunctionMap)) {
|
|
684
|
-
const detectUrlRes = detectUrl(args);
|
|
685
|
-
if (detectUrlRes) {
|
|
686
|
-
return detectUrlRes;
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
return null;
|
|
690
|
-
}
|
|
691
|
-
var NAME_REGEX = /[a-z0-9\-_.+]+/i;
|
|
692
203
|
var parseScmURL = (scmURL, scmType) => {
|
|
693
204
|
try {
|
|
694
205
|
const url = new URL(scmURL);
|
|
@@ -701,41 +212,55 @@ var parseScmURL = (scmURL, scmType) => {
|
|
|
701
212
|
});
|
|
702
213
|
if (!repo)
|
|
703
214
|
return null;
|
|
704
|
-
const { organization, repoName
|
|
215
|
+
const { organization, repoName } = repo;
|
|
705
216
|
if (!organization || !repoName)
|
|
706
217
|
return null;
|
|
707
218
|
if (!organization.match(NAME_REGEX) || !repoName.match(NAME_REGEX))
|
|
708
|
-
return null;
|
|
709
|
-
|
|
710
|
-
hostname,
|
|
711
|
-
organization,
|
|
712
|
-
projectPath,
|
|
713
|
-
repoName,
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
if (pathParts.length > 4)
|
|
730
|
-
return false;
|
|
731
|
-
if (pathParts.some((part) => !part.match(NAME_REGEX)))
|
|
732
|
-
return false;
|
|
733
|
-
return true;
|
|
219
|
+
return null;
|
|
220
|
+
const res = {
|
|
221
|
+
hostname,
|
|
222
|
+
organization,
|
|
223
|
+
projectPath,
|
|
224
|
+
repoName,
|
|
225
|
+
protocol: url.protocol,
|
|
226
|
+
pathElements: projectPath.split("/")
|
|
227
|
+
};
|
|
228
|
+
if (repo.scmType === "Ado" /* Ado */) {
|
|
229
|
+
return {
|
|
230
|
+
projectName: repo.projectName,
|
|
231
|
+
prefixPath: repo.prefixPath,
|
|
232
|
+
scmType: repo.scmType,
|
|
233
|
+
...res
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
scmType: repo.scmType,
|
|
238
|
+
...res
|
|
239
|
+
};
|
|
734
240
|
} catch (e) {
|
|
735
241
|
return null;
|
|
736
242
|
}
|
|
737
243
|
};
|
|
738
244
|
|
|
245
|
+
// src/features/analysis/scm/shared/src/index.ts
|
|
246
|
+
var NAME_REGEX = /[a-z0-9\-_.+]+/i;
|
|
247
|
+
var ADO_PREFIX_PATH = "tfs";
|
|
248
|
+
|
|
249
|
+
// src/features/analysis/scm/types.ts
|
|
250
|
+
var ReferenceType = /* @__PURE__ */ ((ReferenceType2) => {
|
|
251
|
+
ReferenceType2["BRANCH"] = "BRANCH";
|
|
252
|
+
ReferenceType2["COMMIT"] = "COMMIT";
|
|
253
|
+
ReferenceType2["TAG"] = "TAG";
|
|
254
|
+
return ReferenceType2;
|
|
255
|
+
})(ReferenceType || {});
|
|
256
|
+
var ScmLibScmType = /* @__PURE__ */ ((ScmLibScmType2) => {
|
|
257
|
+
ScmLibScmType2["GITHUB"] = "GITHUB";
|
|
258
|
+
ScmLibScmType2["GITLAB"] = "GITLAB";
|
|
259
|
+
ScmLibScmType2["ADO"] = "ADO";
|
|
260
|
+
ScmLibScmType2["BITBUCKET"] = "BITBUCKET";
|
|
261
|
+
return ScmLibScmType2;
|
|
262
|
+
})(ScmLibScmType || {});
|
|
263
|
+
|
|
739
264
|
// src/features/analysis/scm/utils/get_issue_type.ts
|
|
740
265
|
var getIssueType = (issueType) => {
|
|
741
266
|
switch (issueType) {
|
|
@@ -861,6 +386,8 @@ var getIssueType = (issueType) => {
|
|
|
861
386
|
return "Value Never Read";
|
|
862
387
|
case "VALUE_SHADOWING" /* ValueShadowing */:
|
|
863
388
|
return "Value Shadowing";
|
|
389
|
+
case "ERRONEOUS_STRING_COMPARE" /* ErroneousStringCompare */:
|
|
390
|
+
return "Erroneous String Compare";
|
|
864
391
|
default: {
|
|
865
392
|
return issueType ? issueType.replaceAll("_", " ") : "Other";
|
|
866
393
|
}
|
|
@@ -944,6 +471,22 @@ var isUrlHasPath = (url) => {
|
|
|
944
471
|
function shouldValidateUrl(repoUrl) {
|
|
945
472
|
return repoUrl && isUrlHasPath(repoUrl);
|
|
946
473
|
}
|
|
474
|
+
var sanityRepoURL = (scmURL) => {
|
|
475
|
+
try {
|
|
476
|
+
const url = new URL(scmURL);
|
|
477
|
+
const projectPath = url.pathname.substring(1).replace(/.git$/i, "");
|
|
478
|
+
const pathParts = projectPath.split("/");
|
|
479
|
+
if (pathParts.length < 2)
|
|
480
|
+
return false;
|
|
481
|
+
if (pathParts.length > 4 && pathParts.at(0) !== ADO_PREFIX_PATH)
|
|
482
|
+
return false;
|
|
483
|
+
if (pathParts.some((part) => !part.match(NAME_REGEX)))
|
|
484
|
+
return false;
|
|
485
|
+
return true;
|
|
486
|
+
} catch (e) {
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
489
|
+
};
|
|
947
490
|
|
|
948
491
|
// src/features/analysis/scm/bitbucket/bitbucket.ts
|
|
949
492
|
var BITBUCKET_HOSTNAME = "bitbucket.org";
|
|
@@ -2063,7 +1606,7 @@ initGitlabFetchMock();
|
|
|
2063
1606
|
// src/features/analysis/scm/scmSubmit/index.ts
|
|
2064
1607
|
import fs from "node:fs/promises";
|
|
2065
1608
|
import parseDiff from "parse-diff";
|
|
2066
|
-
import
|
|
1609
|
+
import path from "path";
|
|
2067
1610
|
import { simpleGit } from "simple-git";
|
|
2068
1611
|
import tmp from "tmp";
|
|
2069
1612
|
import { z as z6 } from "zod";
|
|
@@ -2195,10 +1738,10 @@ function getCloudScmLibTypeFromUrl(url) {
|
|
|
2195
1738
|
return void 0;
|
|
2196
1739
|
}
|
|
2197
1740
|
var scmCloudHostname = {
|
|
2198
|
-
GitLab: new URL(scmCloudUrl.GitLab).hostname,
|
|
2199
|
-
GitHub: new URL(scmCloudUrl.GitHub).hostname,
|
|
2200
|
-
Ado: new URL(scmCloudUrl.Ado).hostname,
|
|
2201
|
-
Bitbucket: new URL(scmCloudUrl.Bitbucket).hostname
|
|
1741
|
+
["GitLab" /* GitLab */]: new URL(scmCloudUrl.GitLab).hostname,
|
|
1742
|
+
["GitHub" /* GitHub */]: new URL(scmCloudUrl.GitHub).hostname,
|
|
1743
|
+
["Ado" /* Ado */]: new URL(scmCloudUrl.Ado).hostname,
|
|
1744
|
+
["Bitbucket" /* Bitbucket */]: new URL(scmCloudUrl.Bitbucket).hostname
|
|
2202
1745
|
};
|
|
2203
1746
|
var scmLibScmTypeToScmType = {
|
|
2204
1747
|
["GITLAB" /* GITLAB */]: "GitLab" /* GitLab */,
|
|
@@ -2212,10 +1755,6 @@ var scmTypeToScmLibScmType = {
|
|
|
2212
1755
|
["Ado" /* Ado */]: "ADO" /* ADO */,
|
|
2213
1756
|
["Bitbucket" /* Bitbucket */]: "BITBUCKET" /* BITBUCKET */
|
|
2214
1757
|
};
|
|
2215
|
-
function getScmTypeFromScmLibType(scmLibType) {
|
|
2216
|
-
const parsedScmLibType = z7.nativeEnum(ScmLibScmType).parse(scmLibType);
|
|
2217
|
-
return scmLibScmTypeToScmType[parsedScmLibType];
|
|
2218
|
-
}
|
|
2219
1758
|
function getScmLibTypeFromScmType(scmType) {
|
|
2220
1759
|
const parsedScmType = z7.nativeEnum(ScmType).parse(scmType);
|
|
2221
1760
|
return scmTypeToScmLibScmType[parsedScmType];
|
|
@@ -2271,24 +1810,6 @@ function getScmConfig({
|
|
|
2271
1810
|
scmOrg: void 0
|
|
2272
1811
|
};
|
|
2273
1812
|
}
|
|
2274
|
-
async function scmCanReachRepo({
|
|
2275
|
-
repoUrl,
|
|
2276
|
-
scmType,
|
|
2277
|
-
accessToken,
|
|
2278
|
-
scmOrg
|
|
2279
|
-
}) {
|
|
2280
|
-
try {
|
|
2281
|
-
await SCMLib.init({
|
|
2282
|
-
url: repoUrl,
|
|
2283
|
-
accessToken,
|
|
2284
|
-
scmType: getScmLibTypeFromScmType(scmType),
|
|
2285
|
-
scmOrg
|
|
2286
|
-
});
|
|
2287
|
-
return true;
|
|
2288
|
-
} catch (e) {
|
|
2289
|
-
return false;
|
|
2290
|
-
}
|
|
2291
|
-
}
|
|
2292
1813
|
var InvalidRepoUrlError = class extends Error {
|
|
2293
1814
|
constructor(m) {
|
|
2294
1815
|
super(m);
|
|
@@ -2407,12 +1928,7 @@ var SCMLib = class {
|
|
|
2407
1928
|
static async getIsValidBranchName(branchName) {
|
|
2408
1929
|
return isValidBranchName(branchName);
|
|
2409
1930
|
}
|
|
2410
|
-
static async init({
|
|
2411
|
-
url,
|
|
2412
|
-
accessToken,
|
|
2413
|
-
scmType,
|
|
2414
|
-
scmOrg
|
|
2415
|
-
}) {
|
|
1931
|
+
static async init({ url, accessToken, scmType, scmOrg }, { propagateExceptions = false } = {}) {
|
|
2416
1932
|
const trimmedUrl = url ? url.trim().replace(/\/$/, "").replace(/.git$/i, "") : void 0;
|
|
2417
1933
|
try {
|
|
2418
1934
|
switch (scmType) {
|
|
@@ -2428,6 +1944,7 @@ var SCMLib = class {
|
|
|
2428
1944
|
}
|
|
2429
1945
|
case "ADO" /* ADO */: {
|
|
2430
1946
|
const scm = new AdoSCMLib(trimmedUrl, accessToken, scmOrg);
|
|
1947
|
+
await scm.getAdoSdk();
|
|
2431
1948
|
await scm.validateParams();
|
|
2432
1949
|
return scm;
|
|
2433
1950
|
}
|
|
@@ -2445,6 +1962,9 @@ var SCMLib = class {
|
|
|
2445
1962
|
);
|
|
2446
1963
|
}
|
|
2447
1964
|
console.error(`error validating scm: ${scmType} `, e);
|
|
1965
|
+
if (propagateExceptions) {
|
|
1966
|
+
throw e;
|
|
1967
|
+
}
|
|
2448
1968
|
}
|
|
2449
1969
|
return new StubSCMLib(trimmedUrl, void 0, void 0);
|
|
2450
1970
|
}
|
|
@@ -2943,792 +2463,1360 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
2943
2463
|
async postGeneralPrComment(params) {
|
|
2944
2464
|
const { prNumber, body } = params;
|
|
2945
2465
|
this._validateAccessTokenAndUrl();
|
|
2946
|
-
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
2947
|
-
return await this.githubSdk.postGeneralPrComment({
|
|
2948
|
-
issue_number: prNumber,
|
|
2949
|
-
owner,
|
|
2950
|
-
repo,
|
|
2951
|
-
body
|
|
2952
|
-
});
|
|
2466
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
2467
|
+
return await this.githubSdk.postGeneralPrComment({
|
|
2468
|
+
issue_number: prNumber,
|
|
2469
|
+
owner,
|
|
2470
|
+
repo,
|
|
2471
|
+
body
|
|
2472
|
+
});
|
|
2473
|
+
}
|
|
2474
|
+
async getGeneralPrComments(params) {
|
|
2475
|
+
const { prNumber } = params;
|
|
2476
|
+
this._validateAccessTokenAndUrl();
|
|
2477
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
2478
|
+
return await this.githubSdk.getGeneralPrComments({
|
|
2479
|
+
issue_number: prNumber,
|
|
2480
|
+
owner,
|
|
2481
|
+
repo
|
|
2482
|
+
});
|
|
2483
|
+
}
|
|
2484
|
+
async deleteGeneralPrComment({
|
|
2485
|
+
commentId
|
|
2486
|
+
}) {
|
|
2487
|
+
this._validateAccessTokenAndUrl();
|
|
2488
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
2489
|
+
return this.githubSdk.deleteGeneralPrComment({
|
|
2490
|
+
owner,
|
|
2491
|
+
repo,
|
|
2492
|
+
comment_id: commentId
|
|
2493
|
+
});
|
|
2494
|
+
}
|
|
2495
|
+
};
|
|
2496
|
+
var StubSCMLib = class extends SCMLib {
|
|
2497
|
+
async createSubmitRequest(_params) {
|
|
2498
|
+
console.error("createSubmitRequest() not implemented");
|
|
2499
|
+
throw new Error("createSubmitRequest() not implemented");
|
|
2500
|
+
}
|
|
2501
|
+
getScmLibType() {
|
|
2502
|
+
console.error("getScmLibType() not implemented");
|
|
2503
|
+
throw new Error("getScmLibType() not implemented");
|
|
2504
|
+
}
|
|
2505
|
+
getAuthHeaders() {
|
|
2506
|
+
console.error("getAuthHeaders() not implemented");
|
|
2507
|
+
throw new Error("getAuthHeaders() not implemented");
|
|
2508
|
+
}
|
|
2509
|
+
getDownloadUrl(_sha) {
|
|
2510
|
+
console.error("getDownloadUrl() not implemented");
|
|
2511
|
+
throw new Error("getDownloadUrl() not implemented");
|
|
2512
|
+
}
|
|
2513
|
+
async getIsRemoteBranch(_branch) {
|
|
2514
|
+
console.error("getIsRemoteBranch() not implemented");
|
|
2515
|
+
throw new Error("getIsRemoteBranch() not implemented");
|
|
2516
|
+
}
|
|
2517
|
+
async validateParams() {
|
|
2518
|
+
console.error("validateParams() not implemented");
|
|
2519
|
+
throw new Error("validateParams() not implemented");
|
|
2520
|
+
}
|
|
2521
|
+
async getRepoList(_scmOrg) {
|
|
2522
|
+
console.error("getRepoList() not implemented");
|
|
2523
|
+
throw new Error("getRepoList() not implemented");
|
|
2524
|
+
}
|
|
2525
|
+
async getBranchList() {
|
|
2526
|
+
console.error("getBranchList() not implemented");
|
|
2527
|
+
throw new Error("getBranchList() not implemented");
|
|
2528
|
+
}
|
|
2529
|
+
async getUsername() {
|
|
2530
|
+
console.error("getUsername() not implemented");
|
|
2531
|
+
throw new Error("getUsername() not implemented");
|
|
2532
|
+
}
|
|
2533
|
+
async getSubmitRequestStatus(_scmSubmitRequestId) {
|
|
2534
|
+
console.error("getSubmitRequestStatus() not implemented");
|
|
2535
|
+
throw new Error("getSubmitRequestStatus() not implemented");
|
|
2536
|
+
}
|
|
2537
|
+
async getUserHasAccessToRepo() {
|
|
2538
|
+
console.error("getUserHasAccessToRepo() not implemented");
|
|
2539
|
+
throw new Error("getUserHasAccessToRepo() not implemented");
|
|
2540
|
+
}
|
|
2541
|
+
async getRepoBlameRanges(_ref, _path) {
|
|
2542
|
+
console.error("getRepoBlameRanges() not implemented");
|
|
2543
|
+
throw new Error("getRepoBlameRanges() not implemented");
|
|
2544
|
+
}
|
|
2545
|
+
async getReferenceData(_ref) {
|
|
2546
|
+
console.error("getReferenceData() not implemented");
|
|
2547
|
+
throw new Error("getReferenceData() not implemented");
|
|
2548
|
+
}
|
|
2549
|
+
async getRepoDefaultBranch() {
|
|
2550
|
+
console.error("getRepoDefaultBranch() not implemented");
|
|
2551
|
+
throw new Error("getRepoDefaultBranch() not implemented");
|
|
2552
|
+
}
|
|
2553
|
+
async getPrUrl(_prNumber) {
|
|
2554
|
+
console.error("getPr() not implemented");
|
|
2555
|
+
throw new Error("getPr() not implemented");
|
|
2556
|
+
}
|
|
2557
|
+
_getUsernameForAuthUrl() {
|
|
2558
|
+
throw new Error("Method not implemented.");
|
|
2559
|
+
}
|
|
2560
|
+
};
|
|
2561
|
+
function getUserAndPassword(token) {
|
|
2562
|
+
const [username, password] = token.split(":");
|
|
2563
|
+
const safePasswordAndUsername = z7.object({ username: z7.string(), password: z7.string() }).parse({ username, password });
|
|
2564
|
+
return {
|
|
2565
|
+
username: safePasswordAndUsername.username,
|
|
2566
|
+
password: safePasswordAndUsername.password
|
|
2567
|
+
};
|
|
2568
|
+
}
|
|
2569
|
+
function createBitbucketSdk(token) {
|
|
2570
|
+
if (!token) {
|
|
2571
|
+
return getBitbucketSdk({ authType: "public" });
|
|
2572
|
+
}
|
|
2573
|
+
if (token.includes(":")) {
|
|
2574
|
+
const { password, username } = getUserAndPassword(token);
|
|
2575
|
+
return getBitbucketSdk({
|
|
2576
|
+
authType: "basic",
|
|
2577
|
+
username,
|
|
2578
|
+
password
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2581
|
+
return getBitbucketSdk({ authType: "token", token });
|
|
2582
|
+
}
|
|
2583
|
+
var BitbucketSCMLib = class extends SCMLib {
|
|
2584
|
+
constructor(url, accessToken, scmOrg) {
|
|
2585
|
+
super(url, accessToken, scmOrg);
|
|
2586
|
+
__publicField(this, "bitbucketSdk");
|
|
2587
|
+
const bitbucketSdk = createBitbucketSdk(accessToken);
|
|
2588
|
+
this.bitbucketSdk = bitbucketSdk;
|
|
2589
|
+
}
|
|
2590
|
+
getAuthData() {
|
|
2591
|
+
const authType = this.bitbucketSdk.getAuthType();
|
|
2592
|
+
switch (authType) {
|
|
2593
|
+
case "basic": {
|
|
2594
|
+
this._validateAccessToken();
|
|
2595
|
+
const { username, password } = getUserAndPassword(this.accessToken);
|
|
2596
|
+
return { username, password, authType };
|
|
2597
|
+
}
|
|
2598
|
+
case "token": {
|
|
2599
|
+
return { authType, token: z7.string().parse(this.accessToken) };
|
|
2600
|
+
}
|
|
2601
|
+
case "public":
|
|
2602
|
+
return { authType };
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
async createSubmitRequest(params) {
|
|
2606
|
+
this._validateAccessTokenAndUrl();
|
|
2607
|
+
const pullRequestRes = await this.bitbucketSdk.createPullRequest({
|
|
2608
|
+
...params,
|
|
2609
|
+
repoUrl: this.url
|
|
2610
|
+
});
|
|
2611
|
+
return String(z7.number().parse(pullRequestRes.id));
|
|
2612
|
+
}
|
|
2613
|
+
async validateParams() {
|
|
2614
|
+
return validateBitbucketParams({
|
|
2615
|
+
bitbucketClient: this.bitbucketSdk,
|
|
2616
|
+
url: this.url
|
|
2617
|
+
});
|
|
2618
|
+
}
|
|
2619
|
+
async getRepoList(scmOrg) {
|
|
2620
|
+
this._validateAccessToken();
|
|
2621
|
+
return this.bitbucketSdk.getRepos({
|
|
2622
|
+
workspaceSlug: scmOrg
|
|
2623
|
+
});
|
|
2624
|
+
}
|
|
2625
|
+
async getBranchList() {
|
|
2626
|
+
this._validateAccessTokenAndUrl();
|
|
2627
|
+
return this.bitbucketSdk.getBranchList({
|
|
2628
|
+
repoUrl: this.url
|
|
2629
|
+
});
|
|
2630
|
+
}
|
|
2631
|
+
getScmLibType() {
|
|
2632
|
+
return "BITBUCKET" /* BITBUCKET */;
|
|
2633
|
+
}
|
|
2634
|
+
getAuthHeaders() {
|
|
2635
|
+
const authType = this.bitbucketSdk.getAuthType();
|
|
2636
|
+
switch (authType) {
|
|
2637
|
+
case "public":
|
|
2638
|
+
return {};
|
|
2639
|
+
case "token":
|
|
2640
|
+
return { authorization: `Bearer ${this.accessToken}` };
|
|
2641
|
+
case "basic": {
|
|
2642
|
+
this._validateAccessToken();
|
|
2643
|
+
const { username, password } = getUserAndPassword(this.accessToken);
|
|
2644
|
+
return {
|
|
2645
|
+
authorization: `Basic ${Buffer.from(
|
|
2646
|
+
username + ":" + password
|
|
2647
|
+
).toString("base64")}`
|
|
2648
|
+
};
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
async getDownloadUrl(sha) {
|
|
2653
|
+
this._validateUrl();
|
|
2654
|
+
return this.bitbucketSdk.getDownloadUrl({ url: this.url, sha });
|
|
2655
|
+
}
|
|
2656
|
+
async _getUsernameForAuthUrl() {
|
|
2657
|
+
this._validateAccessTokenAndUrl();
|
|
2658
|
+
const user = await this.bitbucketSdk.getUser();
|
|
2659
|
+
if (!user.username) {
|
|
2660
|
+
throw new Error("no username found");
|
|
2661
|
+
}
|
|
2662
|
+
return user.username;
|
|
2953
2663
|
}
|
|
2954
|
-
async
|
|
2955
|
-
const { prNumber } = params;
|
|
2664
|
+
async getIsRemoteBranch(branch) {
|
|
2956
2665
|
this._validateAccessTokenAndUrl();
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2666
|
+
try {
|
|
2667
|
+
const res = await this.bitbucketSdk.getBranch({
|
|
2668
|
+
branchName: branch,
|
|
2669
|
+
repoUrl: this.url
|
|
2670
|
+
});
|
|
2671
|
+
return res.name === branch;
|
|
2672
|
+
} catch (e) {
|
|
2673
|
+
return false;
|
|
2674
|
+
}
|
|
2963
2675
|
}
|
|
2964
|
-
async
|
|
2965
|
-
commentId
|
|
2966
|
-
}) {
|
|
2676
|
+
async getUserHasAccessToRepo() {
|
|
2967
2677
|
this._validateAccessTokenAndUrl();
|
|
2968
|
-
|
|
2969
|
-
return this.githubSdk.deleteGeneralPrComment({
|
|
2970
|
-
owner,
|
|
2971
|
-
repo,
|
|
2972
|
-
comment_id: commentId
|
|
2973
|
-
});
|
|
2678
|
+
return this.bitbucketSdk.getIsUserCollaborator({ repoUrl: this.url });
|
|
2974
2679
|
}
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
throw new Error("createSubmitRequest() not implemented");
|
|
2680
|
+
async getUsername() {
|
|
2681
|
+
this._validateAccessToken();
|
|
2682
|
+
const res = await this.bitbucketSdk.getUser();
|
|
2683
|
+
return z7.string().parse(res.username);
|
|
2980
2684
|
}
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2685
|
+
async getSubmitRequestStatus(_scmSubmitRequestId) {
|
|
2686
|
+
this._validateAccessTokenAndUrl();
|
|
2687
|
+
const pullRequestRes = await this.bitbucketSdk.getPullRequest({
|
|
2688
|
+
prNumber: Number(_scmSubmitRequestId),
|
|
2689
|
+
url: this.url
|
|
2690
|
+
});
|
|
2691
|
+
switch (pullRequestRes.state) {
|
|
2692
|
+
case "OPEN":
|
|
2693
|
+
return "open";
|
|
2694
|
+
case "MERGED":
|
|
2695
|
+
return "merged";
|
|
2696
|
+
case "DECLINED":
|
|
2697
|
+
return "closed";
|
|
2698
|
+
default:
|
|
2699
|
+
throw new Error(`unknown state ${pullRequestRes.state} `);
|
|
2700
|
+
}
|
|
2984
2701
|
}
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
throw new Error("getAuthHeaders() not implemented");
|
|
2702
|
+
async getRepoBlameRanges(_ref, _path) {
|
|
2703
|
+
return [];
|
|
2988
2704
|
}
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2705
|
+
async getReferenceData(ref) {
|
|
2706
|
+
this._validateUrl();
|
|
2707
|
+
return this.bitbucketSdk.getReferenceData({ url: this.url, ref });
|
|
2992
2708
|
}
|
|
2993
|
-
async
|
|
2994
|
-
|
|
2995
|
-
|
|
2709
|
+
async getRepoDefaultBranch() {
|
|
2710
|
+
this._validateUrl();
|
|
2711
|
+
const repoRes = await this.bitbucketSdk.getRepo({ repoUrl: this.url });
|
|
2712
|
+
return z7.string().parse(repoRes.mainbranch?.name);
|
|
2996
2713
|
}
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
2714
|
+
getPrUrl(prNumber) {
|
|
2715
|
+
this._validateUrl();
|
|
2716
|
+
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(this.url);
|
|
2717
|
+
return Promise.resolve(
|
|
2718
|
+
`https://bitbucket.org/${workspace}/${repoSlug}/pull-requests/${prNumber}`
|
|
2719
|
+
);
|
|
3000
2720
|
}
|
|
3001
|
-
async
|
|
3002
|
-
|
|
3003
|
-
|
|
2721
|
+
async refreshToken(params) {
|
|
2722
|
+
const getBitbucketTokenResponse = await getBitbucketToken({
|
|
2723
|
+
authType: "refresh_token",
|
|
2724
|
+
...params
|
|
2725
|
+
});
|
|
2726
|
+
return {
|
|
2727
|
+
accessToken: getBitbucketTokenResponse.access_token,
|
|
2728
|
+
refreshToken: getBitbucketTokenResponse.refresh_token
|
|
2729
|
+
};
|
|
3004
2730
|
}
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
2731
|
+
};
|
|
2732
|
+
|
|
2733
|
+
// src/features/analysis/scm/ado/validation.ts
|
|
2734
|
+
import { z as z8 } from "zod";
|
|
2735
|
+
var ValidPullRequestStatusZ = z8.union([
|
|
2736
|
+
z8.literal(1 /* Active */),
|
|
2737
|
+
z8.literal(2 /* Abandoned */),
|
|
2738
|
+
z8.literal(3 /* Completed */)
|
|
2739
|
+
]);
|
|
2740
|
+
var AdoAuthResultZ = z8.object({
|
|
2741
|
+
access_token: z8.string().min(1),
|
|
2742
|
+
token_type: z8.string().min(1),
|
|
2743
|
+
refresh_token: z8.string().min(1)
|
|
2744
|
+
});
|
|
2745
|
+
var profileZ = z8.object({
|
|
2746
|
+
displayName: z8.string(),
|
|
2747
|
+
publicAlias: z8.string().min(1),
|
|
2748
|
+
emailAddress: z8.string(),
|
|
2749
|
+
coreRevision: z8.number(),
|
|
2750
|
+
timeStamp: z8.string(),
|
|
2751
|
+
id: z8.string(),
|
|
2752
|
+
revision: z8.number()
|
|
2753
|
+
});
|
|
2754
|
+
var accountsZ = z8.object({
|
|
2755
|
+
count: z8.number(),
|
|
2756
|
+
value: z8.array(
|
|
2757
|
+
z8.object({
|
|
2758
|
+
accountId: z8.string(),
|
|
2759
|
+
accountUri: z8.string(),
|
|
2760
|
+
accountName: z8.string()
|
|
2761
|
+
})
|
|
2762
|
+
)
|
|
2763
|
+
});
|
|
2764
|
+
|
|
2765
|
+
// src/features/analysis/scm/ado/utils.ts
|
|
2766
|
+
function _getPublicAdoClient({
|
|
2767
|
+
orgName,
|
|
2768
|
+
origin: origin2
|
|
2769
|
+
}) {
|
|
2770
|
+
const orgUrl = `${origin2}/${orgName}`;
|
|
2771
|
+
const authHandler = api.getPersonalAccessTokenHandler("");
|
|
2772
|
+
authHandler.canHandleAuthentication = () => false;
|
|
2773
|
+
authHandler.prepareRequest = (_options) => {
|
|
2774
|
+
return;
|
|
2775
|
+
};
|
|
2776
|
+
const connection = new api.WebApi(orgUrl, authHandler);
|
|
2777
|
+
return connection;
|
|
2778
|
+
}
|
|
2779
|
+
function removeTrailingSlash2(str) {
|
|
2780
|
+
return str.trim().replace(/\/+$/, "");
|
|
2781
|
+
}
|
|
2782
|
+
function parseAdoOwnerAndRepo(adoUrl) {
|
|
2783
|
+
adoUrl = removeTrailingSlash2(adoUrl);
|
|
2784
|
+
const parsingResult = parseScmURL(adoUrl, "Ado" /* Ado */);
|
|
2785
|
+
if (!parsingResult || parsingResult.scmType !== "Ado" /* Ado */) {
|
|
2786
|
+
throw new InvalidUrlPatternError(`
|
|
2787
|
+
: ${adoUrl}`);
|
|
3008
2788
|
}
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
2789
|
+
const {
|
|
2790
|
+
organization,
|
|
2791
|
+
repoName,
|
|
2792
|
+
projectName,
|
|
2793
|
+
projectPath,
|
|
2794
|
+
pathElements,
|
|
2795
|
+
hostname,
|
|
2796
|
+
protocol
|
|
2797
|
+
} = parsingResult;
|
|
2798
|
+
return {
|
|
2799
|
+
owner: decodeURI(organization),
|
|
2800
|
+
repo: decodeURI(repoName),
|
|
2801
|
+
projectName: projectName ? decodeURI(projectName) : void 0,
|
|
2802
|
+
projectPath,
|
|
2803
|
+
pathElements,
|
|
2804
|
+
prefixPath: parsingResult.prefixPath,
|
|
2805
|
+
origin: `${protocol}//${hostname}`
|
|
2806
|
+
};
|
|
2807
|
+
}
|
|
2808
|
+
async function getAdoConnectData({
|
|
2809
|
+
url,
|
|
2810
|
+
tokenOrg,
|
|
2811
|
+
adoTokenInfo
|
|
2812
|
+
}) {
|
|
2813
|
+
if (url) {
|
|
2814
|
+
const urlObject = new URL(url);
|
|
2815
|
+
if (tokenOrg && (urlObject.origin === url || `${urlObject.origin}/tfs` === url)) {
|
|
2816
|
+
return {
|
|
2817
|
+
origin: url,
|
|
2818
|
+
org: tokenOrg
|
|
2819
|
+
};
|
|
2820
|
+
}
|
|
2821
|
+
const { owner, origin: origin2, prefixPath } = parseAdoOwnerAndRepo(url);
|
|
2822
|
+
return {
|
|
2823
|
+
org: owner,
|
|
2824
|
+
origin: prefixPath ? `${origin2}/${prefixPath}` : origin2
|
|
2825
|
+
};
|
|
3012
2826
|
}
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
2827
|
+
if (!tokenOrg) {
|
|
2828
|
+
if (adoTokenInfo.type === "OAUTH" /* OAUTH */) {
|
|
2829
|
+
const [org] = await _getOrgsForOauthToken({
|
|
2830
|
+
oauthToken: adoTokenInfo.accessToken
|
|
2831
|
+
});
|
|
2832
|
+
return {
|
|
2833
|
+
org: z9.string().parse(org),
|
|
2834
|
+
origin: DEFUALT_ADO_ORIGIN
|
|
2835
|
+
};
|
|
2836
|
+
}
|
|
2837
|
+
throw new InvalidRepoUrlError("ADO URL is null");
|
|
3016
2838
|
}
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
2839
|
+
return {
|
|
2840
|
+
org: tokenOrg,
|
|
2841
|
+
origin: DEFUALT_ADO_ORIGIN
|
|
2842
|
+
};
|
|
2843
|
+
}
|
|
2844
|
+
function isAdoOnCloud(url) {
|
|
2845
|
+
const urlObj = new URL(url);
|
|
2846
|
+
return urlObj.origin.toLowerCase() === DEFUALT_ADO_ORIGIN || urlObj.hostname.toLowerCase().endsWith(".visualstudio.com");
|
|
2847
|
+
}
|
|
2848
|
+
async function getAdoApiClient(params) {
|
|
2849
|
+
const { origin: origin2 = DEFUALT_ADO_ORIGIN, orgName } = params;
|
|
2850
|
+
if (params.tokenType === "NONE" /* NONE */ || // note: move to public client if the token is not associated with the PAT org
|
|
2851
|
+
// we're only doing it the ado on the cloud
|
|
2852
|
+
params.tokenType === "PAT" /* PAT */ && params.patTokenOrg !== orgName && isAdoOnCloud(origin2)) {
|
|
2853
|
+
return _getPublicAdoClient({ orgName, origin: origin2 });
|
|
3020
2854
|
}
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
2855
|
+
const orgUrl = `${origin2}/${orgName}`;
|
|
2856
|
+
if (params.tokenType === "OAUTH" /* OAUTH */) {
|
|
2857
|
+
if (!isAdoOnCloud(origin2)) {
|
|
2858
|
+
throw new Error(
|
|
2859
|
+
`Oauth token is not supported for ADO on prem - ${origin2} `
|
|
2860
|
+
);
|
|
2861
|
+
}
|
|
2862
|
+
const connection2 = new api.WebApi(
|
|
2863
|
+
orgUrl,
|
|
2864
|
+
api.getBearerHandler(params.accessToken),
|
|
2865
|
+
{}
|
|
2866
|
+
);
|
|
2867
|
+
return connection2;
|
|
3024
2868
|
}
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
2869
|
+
const authHandler = api.getPersonalAccessTokenHandler(params.accessToken);
|
|
2870
|
+
const isBroker = BROKERED_HOSTS.includes(new URL(orgUrl).origin);
|
|
2871
|
+
const connection = new api.WebApi(
|
|
2872
|
+
orgUrl,
|
|
2873
|
+
authHandler,
|
|
2874
|
+
isBroker ? {
|
|
2875
|
+
proxy: {
|
|
2876
|
+
proxyUrl: GIT_PROXY_HOST
|
|
2877
|
+
},
|
|
2878
|
+
ignoreSslError: true
|
|
2879
|
+
} : void 0
|
|
2880
|
+
);
|
|
2881
|
+
return connection;
|
|
2882
|
+
}
|
|
2883
|
+
function getAdoTokenInfo(token) {
|
|
2884
|
+
if (!token) {
|
|
2885
|
+
return { type: "NONE" /* NONE */ };
|
|
3028
2886
|
}
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
throw new Error("getRepoDefaultBranch() not implemented");
|
|
2887
|
+
if (token.includes(".")) {
|
|
2888
|
+
return { type: "OAUTH" /* OAUTH */, accessToken: token };
|
|
3032
2889
|
}
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
2890
|
+
return { type: "PAT" /* PAT */, accessToken: token };
|
|
2891
|
+
}
|
|
2892
|
+
async function getAdoClientParams(params) {
|
|
2893
|
+
const { url, accessToken, tokenOrg } = params;
|
|
2894
|
+
const adoTokenInfo = getAdoTokenInfo(accessToken);
|
|
2895
|
+
const { org, origin: origin2 } = await getAdoConnectData({
|
|
2896
|
+
url,
|
|
2897
|
+
tokenOrg,
|
|
2898
|
+
adoTokenInfo
|
|
2899
|
+
});
|
|
2900
|
+
switch (adoTokenInfo.type) {
|
|
2901
|
+
case "NONE" /* NONE */:
|
|
2902
|
+
return {
|
|
2903
|
+
tokenType: "NONE" /* NONE */,
|
|
2904
|
+
origin: origin2,
|
|
2905
|
+
orgName: org.toLowerCase()
|
|
2906
|
+
};
|
|
2907
|
+
case "OAUTH" /* OAUTH */: {
|
|
2908
|
+
return {
|
|
2909
|
+
tokenType: "OAUTH" /* OAUTH */,
|
|
2910
|
+
accessToken: adoTokenInfo.accessToken,
|
|
2911
|
+
origin: origin2,
|
|
2912
|
+
orgName: org.toLowerCase()
|
|
2913
|
+
};
|
|
2914
|
+
}
|
|
2915
|
+
case "PAT" /* PAT */: {
|
|
2916
|
+
return {
|
|
2917
|
+
tokenType: "PAT" /* PAT */,
|
|
2918
|
+
accessToken: adoTokenInfo.accessToken,
|
|
2919
|
+
patTokenOrg: z9.string().parse(tokenOrg).toLowerCase(),
|
|
2920
|
+
origin: origin2,
|
|
2921
|
+
orgName: org.toLowerCase()
|
|
2922
|
+
};
|
|
2923
|
+
}
|
|
3036
2924
|
}
|
|
3037
|
-
|
|
3038
|
-
|
|
2925
|
+
}
|
|
2926
|
+
async function adoValidateParams({
|
|
2927
|
+
url,
|
|
2928
|
+
accessToken,
|
|
2929
|
+
tokenOrg
|
|
2930
|
+
}) {
|
|
2931
|
+
try {
|
|
2932
|
+
const api2 = await getAdoApiClient(
|
|
2933
|
+
await getAdoClientParams({ url, accessToken, tokenOrg })
|
|
2934
|
+
);
|
|
2935
|
+
await api2.connect();
|
|
2936
|
+
} catch (e) {
|
|
2937
|
+
console.log("adoValidateParams error", e);
|
|
2938
|
+
const error = e;
|
|
2939
|
+
const code = error.code || error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
|
|
2940
|
+
const description = error.description || `${e}`;
|
|
2941
|
+
if (code === 401 || code === 403 || description.includes("401") || description.includes("403")) {
|
|
2942
|
+
throw new InvalidAccessTokenError(`invalid ADO access token`);
|
|
2943
|
+
}
|
|
2944
|
+
if (code === 404 || description.includes("404") || description.includes("Not Found")) {
|
|
2945
|
+
throw new InvalidRepoUrlError(`invalid ADO repo URL ${url}`);
|
|
2946
|
+
}
|
|
2947
|
+
throw e;
|
|
3039
2948
|
}
|
|
3040
|
-
}
|
|
3041
|
-
function
|
|
3042
|
-
|
|
3043
|
-
|
|
2949
|
+
}
|
|
2950
|
+
async function _getOrgsForOauthToken({
|
|
2951
|
+
oauthToken
|
|
2952
|
+
}) {
|
|
2953
|
+
const profileRes = await fetch(
|
|
2954
|
+
"https://app.vssps.visualstudio.com/_apis/profile/profiles/me?api-version=6.0",
|
|
2955
|
+
{
|
|
2956
|
+
method: "GET",
|
|
2957
|
+
headers: {
|
|
2958
|
+
Authorization: `Bearer ${oauthToken}`
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
);
|
|
2962
|
+
const profileJson = await profileRes.json();
|
|
2963
|
+
const profile = profileZ.parse(profileJson);
|
|
2964
|
+
const accountsRes = await fetch(
|
|
2965
|
+
`https://app.vssps.visualstudio.com/_apis/accounts?memberId=${profile.publicAlias}&api-version=6.0`,
|
|
2966
|
+
{
|
|
2967
|
+
method: "GET",
|
|
2968
|
+
headers: {
|
|
2969
|
+
Authorization: `Bearer ${oauthToken}`
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
);
|
|
2973
|
+
const accountsJson = await accountsRes.json();
|
|
2974
|
+
const accounts = accountsZ.parse(accountsJson);
|
|
2975
|
+
const orgs = accounts.value.map((account) => account.accountName).filter((value, index, array) => array.indexOf(value) === index);
|
|
2976
|
+
return orgs;
|
|
2977
|
+
}
|
|
2978
|
+
|
|
2979
|
+
// src/features/analysis/scm/ado/ado.ts
|
|
2980
|
+
async function getAdoSdk(params) {
|
|
2981
|
+
const api2 = await getAdoApiClient(params);
|
|
3044
2982
|
return {
|
|
3045
|
-
|
|
3046
|
-
|
|
2983
|
+
async getAdoIsUserCollaborator({ repoUrl }) {
|
|
2984
|
+
try {
|
|
2985
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
2986
|
+
const git = await api2.getGitApi();
|
|
2987
|
+
const branches = await git.getBranches(repo, projectName);
|
|
2988
|
+
if (!branches || branches.length === 0) {
|
|
2989
|
+
throw new InvalidRepoUrlError("no branches");
|
|
2990
|
+
}
|
|
2991
|
+
return true;
|
|
2992
|
+
} catch (e) {
|
|
2993
|
+
return false;
|
|
2994
|
+
}
|
|
2995
|
+
},
|
|
2996
|
+
async getAdoPullRequestStatus({
|
|
2997
|
+
repoUrl,
|
|
2998
|
+
prNumber
|
|
2999
|
+
}) {
|
|
3000
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3001
|
+
const git = await api2.getGitApi();
|
|
3002
|
+
const res = await git.getPullRequest(repo, prNumber, projectName);
|
|
3003
|
+
const parsedPullRequestStatus = ValidPullRequestStatusZ.safeParse(
|
|
3004
|
+
res.status
|
|
3005
|
+
);
|
|
3006
|
+
if (!parsedPullRequestStatus.success) {
|
|
3007
|
+
throw new Error("bad pr status for ADO");
|
|
3008
|
+
}
|
|
3009
|
+
return parsedPullRequestStatus.data;
|
|
3010
|
+
},
|
|
3011
|
+
async getAdoIsRemoteBranch({
|
|
3012
|
+
repoUrl,
|
|
3013
|
+
branch
|
|
3014
|
+
}) {
|
|
3015
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3016
|
+
const git = await api2.getGitApi();
|
|
3017
|
+
try {
|
|
3018
|
+
const branchStatus = await git.getBranch(repo, branch, projectName);
|
|
3019
|
+
if (!branchStatus || !branchStatus.commit) {
|
|
3020
|
+
throw new InvalidRepoUrlError("no branch status");
|
|
3021
|
+
}
|
|
3022
|
+
return branchStatus.name === branch;
|
|
3023
|
+
} catch (e) {
|
|
3024
|
+
return false;
|
|
3025
|
+
}
|
|
3026
|
+
},
|
|
3027
|
+
async getAdoPrUrl({ url, prNumber }) {
|
|
3028
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(url);
|
|
3029
|
+
const git = await api2.getGitApi();
|
|
3030
|
+
const getRepositoryRes = await git.getRepository(
|
|
3031
|
+
decodeURI(repo),
|
|
3032
|
+
projectName ? decodeURI(projectName) : void 0
|
|
3033
|
+
);
|
|
3034
|
+
return `${getRepositoryRes.webUrl}/pullrequest/${prNumber}`;
|
|
3035
|
+
},
|
|
3036
|
+
getAdoDownloadUrl({
|
|
3037
|
+
repoUrl,
|
|
3038
|
+
branch
|
|
3039
|
+
}) {
|
|
3040
|
+
const { owner, repo, projectName, prefixPath } = parseAdoOwnerAndRepo(repoUrl);
|
|
3041
|
+
const url = new URL(repoUrl);
|
|
3042
|
+
const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
|
|
3043
|
+
const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
|
|
3044
|
+
const path9 = [
|
|
3045
|
+
prefixPath,
|
|
3046
|
+
owner,
|
|
3047
|
+
projectName,
|
|
3048
|
+
"_apis",
|
|
3049
|
+
"git",
|
|
3050
|
+
"repositories",
|
|
3051
|
+
repo,
|
|
3052
|
+
"items",
|
|
3053
|
+
"items"
|
|
3054
|
+
].filter(Boolean).join("/");
|
|
3055
|
+
return new URL(`${path9}?${params2}`, origin2).toString();
|
|
3056
|
+
},
|
|
3057
|
+
async getAdoBranchList({ repoUrl }) {
|
|
3058
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3059
|
+
const git = await api2.getGitApi();
|
|
3060
|
+
try {
|
|
3061
|
+
const res = await git.getBranches(repo, projectName);
|
|
3062
|
+
res.sort((a, b) => {
|
|
3063
|
+
if (!a.commit?.committer?.date || !b.commit?.committer?.date) {
|
|
3064
|
+
return 0;
|
|
3065
|
+
}
|
|
3066
|
+
return b.commit?.committer?.date.getTime() - a.commit?.committer?.date.getTime();
|
|
3067
|
+
});
|
|
3068
|
+
return res.reduce((acc, branch) => {
|
|
3069
|
+
if (!branch.name) {
|
|
3070
|
+
return acc;
|
|
3071
|
+
}
|
|
3072
|
+
acc.push(branch.name);
|
|
3073
|
+
return acc;
|
|
3074
|
+
}, []);
|
|
3075
|
+
} catch (e) {
|
|
3076
|
+
return [];
|
|
3077
|
+
}
|
|
3078
|
+
},
|
|
3079
|
+
async createAdoPullRequest(options) {
|
|
3080
|
+
const { repoUrl, sourceBranchName, targetBranchName, title, body } = options;
|
|
3081
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3082
|
+
const git = await api2.getGitApi();
|
|
3083
|
+
const res = await git.createPullRequest(
|
|
3084
|
+
{
|
|
3085
|
+
sourceRefName: `refs/heads/${sourceBranchName}`,
|
|
3086
|
+
targetRefName: `refs/heads/${targetBranchName}`,
|
|
3087
|
+
title,
|
|
3088
|
+
description: body
|
|
3089
|
+
},
|
|
3090
|
+
repo,
|
|
3091
|
+
projectName
|
|
3092
|
+
);
|
|
3093
|
+
return res.pullRequestId;
|
|
3094
|
+
},
|
|
3095
|
+
async getAdoRepoDefaultBranch({
|
|
3096
|
+
repoUrl
|
|
3097
|
+
}) {
|
|
3098
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3099
|
+
const git = await api2.getGitApi();
|
|
3100
|
+
const getRepositoryRes = await git.getRepository(
|
|
3101
|
+
decodeURI(repo),
|
|
3102
|
+
projectName ? decodeURI(projectName) : void 0
|
|
3103
|
+
);
|
|
3104
|
+
if (!getRepositoryRes?.defaultBranch) {
|
|
3105
|
+
throw new InvalidRepoUrlError("no default branch");
|
|
3106
|
+
}
|
|
3107
|
+
return getRepositoryRes.defaultBranch.replace("refs/heads/", "");
|
|
3108
|
+
},
|
|
3109
|
+
// todo: refactor this function
|
|
3110
|
+
async getAdoReferenceData({
|
|
3111
|
+
ref,
|
|
3112
|
+
repoUrl
|
|
3113
|
+
}) {
|
|
3114
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3115
|
+
if (!projectName) {
|
|
3116
|
+
throw new InvalidUrlPatternError("no project name");
|
|
3117
|
+
}
|
|
3118
|
+
const git = await api2.getGitApi();
|
|
3119
|
+
const results = await Promise.allSettled([
|
|
3120
|
+
(async () => {
|
|
3121
|
+
const res = await git.getBranch(repo, ref, projectName);
|
|
3122
|
+
if (!res.commit || !res.commit.commitId) {
|
|
3123
|
+
throw new InvalidRepoUrlError("no commit on branch");
|
|
3124
|
+
}
|
|
3125
|
+
return {
|
|
3126
|
+
sha: res.commit.commitId,
|
|
3127
|
+
type: "BRANCH" /* BRANCH */,
|
|
3128
|
+
date: res.commit.committer?.date || /* @__PURE__ */ new Date()
|
|
3129
|
+
};
|
|
3130
|
+
})(),
|
|
3131
|
+
(async () => {
|
|
3132
|
+
const res = await git.getCommits(
|
|
3133
|
+
repo,
|
|
3134
|
+
{
|
|
3135
|
+
fromCommitId: ref,
|
|
3136
|
+
toCommitId: ref,
|
|
3137
|
+
$top: 1
|
|
3138
|
+
},
|
|
3139
|
+
projectName
|
|
3140
|
+
);
|
|
3141
|
+
const commit = res[0];
|
|
3142
|
+
if (!commit || !commit.commitId) {
|
|
3143
|
+
throw new Error("no commit");
|
|
3144
|
+
}
|
|
3145
|
+
return {
|
|
3146
|
+
sha: commit.commitId,
|
|
3147
|
+
type: "COMMIT" /* COMMIT */,
|
|
3148
|
+
date: commit.committer?.date || /* @__PURE__ */ new Date()
|
|
3149
|
+
};
|
|
3150
|
+
})(),
|
|
3151
|
+
(async () => {
|
|
3152
|
+
const res = await git.getRefs(repo, projectName, `tags/${ref}`);
|
|
3153
|
+
if (!res[0] || !res[0].objectId) {
|
|
3154
|
+
throw new Error("no tag ref");
|
|
3155
|
+
}
|
|
3156
|
+
let objectId = res[0].objectId;
|
|
3157
|
+
try {
|
|
3158
|
+
const tag = await git.getAnnotatedTag(projectName, repo, objectId);
|
|
3159
|
+
if (tag.taggedObject?.objectId) {
|
|
3160
|
+
objectId = tag.taggedObject.objectId;
|
|
3161
|
+
}
|
|
3162
|
+
} catch (e) {
|
|
3163
|
+
}
|
|
3164
|
+
const commitRes2 = await git.getCommits(
|
|
3165
|
+
repo,
|
|
3166
|
+
{
|
|
3167
|
+
fromCommitId: objectId,
|
|
3168
|
+
toCommitId: objectId,
|
|
3169
|
+
$top: 1
|
|
3170
|
+
},
|
|
3171
|
+
projectName
|
|
3172
|
+
);
|
|
3173
|
+
const commit = commitRes2[0];
|
|
3174
|
+
if (!commit) {
|
|
3175
|
+
throw new Error("no commit");
|
|
3176
|
+
}
|
|
3177
|
+
return {
|
|
3178
|
+
sha: objectId,
|
|
3179
|
+
type: "TAG" /* TAG */,
|
|
3180
|
+
date: commit.committer?.date || /* @__PURE__ */ new Date()
|
|
3181
|
+
};
|
|
3182
|
+
})()
|
|
3183
|
+
]);
|
|
3184
|
+
const [branchRes, commitRes, tagRes] = results;
|
|
3185
|
+
if (tagRes.status === "fulfilled") {
|
|
3186
|
+
return tagRes.value;
|
|
3187
|
+
}
|
|
3188
|
+
if (branchRes.status === "fulfilled") {
|
|
3189
|
+
return branchRes.value;
|
|
3190
|
+
}
|
|
3191
|
+
if (commitRes.status === "fulfilled") {
|
|
3192
|
+
return commitRes.value;
|
|
3193
|
+
}
|
|
3194
|
+
throw new RefNotFoundError(`ref: ${ref} does not exist`);
|
|
3195
|
+
},
|
|
3196
|
+
getAdoBlameRanges() {
|
|
3197
|
+
return [];
|
|
3198
|
+
}
|
|
3047
3199
|
};
|
|
3048
3200
|
}
|
|
3049
|
-
function
|
|
3050
|
-
|
|
3051
|
-
|
|
3201
|
+
async function getAdoRepoList({
|
|
3202
|
+
orgName,
|
|
3203
|
+
tokenOrg,
|
|
3204
|
+
accessToken
|
|
3205
|
+
}) {
|
|
3206
|
+
let orgs = [];
|
|
3207
|
+
const adoTokenInfo = getAdoTokenInfo(accessToken);
|
|
3208
|
+
if (adoTokenInfo.type === "NONE" /* NONE */) {
|
|
3209
|
+
return [];
|
|
3052
3210
|
}
|
|
3053
|
-
if (
|
|
3054
|
-
|
|
3055
|
-
return getBitbucketSdk({
|
|
3056
|
-
authType: "basic",
|
|
3057
|
-
username,
|
|
3058
|
-
password
|
|
3059
|
-
});
|
|
3211
|
+
if (adoTokenInfo.type === "OAUTH" /* OAUTH */) {
|
|
3212
|
+
orgs = await _getOrgsForOauthToken({ oauthToken: accessToken });
|
|
3060
3213
|
}
|
|
3061
|
-
|
|
3214
|
+
if (orgs.length === 0 && !orgName) {
|
|
3215
|
+
throw new Error(`no orgs for ADO`);
|
|
3216
|
+
} else if (orgs.length === 0 && orgName) {
|
|
3217
|
+
orgs = [orgName];
|
|
3218
|
+
}
|
|
3219
|
+
const repos = (await Promise.allSettled(
|
|
3220
|
+
orgs.map(async (org) => {
|
|
3221
|
+
const orgApi = await getAdoApiClient({
|
|
3222
|
+
...await getAdoClientParams({
|
|
3223
|
+
accessToken,
|
|
3224
|
+
tokenOrg: tokenOrg || org,
|
|
3225
|
+
url: void 0
|
|
3226
|
+
}),
|
|
3227
|
+
orgName: org
|
|
3228
|
+
});
|
|
3229
|
+
const gitOrg = await orgApi.getGitApi();
|
|
3230
|
+
const orgRepos = await gitOrg.getRepositories();
|
|
3231
|
+
const repoInfoList = (await Promise.allSettled(
|
|
3232
|
+
orgRepos.map(async (repo) => {
|
|
3233
|
+
if (!repo.name || !repo.remoteUrl || !repo.defaultBranch) {
|
|
3234
|
+
throw new InvalidRepoUrlError("bad repo");
|
|
3235
|
+
}
|
|
3236
|
+
const branch = await gitOrg.getBranch(
|
|
3237
|
+
repo.name,
|
|
3238
|
+
repo.defaultBranch.replace(/^refs\/heads\//, ""),
|
|
3239
|
+
repo.project?.name
|
|
3240
|
+
);
|
|
3241
|
+
return {
|
|
3242
|
+
repoName: repo.name,
|
|
3243
|
+
repoUrl: repo.remoteUrl.replace(
|
|
3244
|
+
/^[hH][tT][tT][pP][sS]:\/\/[^/]+@/,
|
|
3245
|
+
"https://"
|
|
3246
|
+
),
|
|
3247
|
+
repoOwner: org,
|
|
3248
|
+
repoIsPublic: repo.project?.visibility === 2 /* Public */,
|
|
3249
|
+
repoLanguages: [],
|
|
3250
|
+
repoUpdatedAt: branch.commit?.committer?.date?.toDateString() || repo.project?.lastUpdateTime?.toDateString() || (/* @__PURE__ */ new Date()).toDateString()
|
|
3251
|
+
};
|
|
3252
|
+
})
|
|
3253
|
+
)).reduce((acc, res) => {
|
|
3254
|
+
if (res.status === "fulfilled") {
|
|
3255
|
+
acc.push(res.value);
|
|
3256
|
+
}
|
|
3257
|
+
return acc;
|
|
3258
|
+
}, []);
|
|
3259
|
+
return repoInfoList;
|
|
3260
|
+
})
|
|
3261
|
+
)).reduce((acc, res) => {
|
|
3262
|
+
if (res.status === "fulfilled") {
|
|
3263
|
+
return acc.concat(res.value);
|
|
3264
|
+
}
|
|
3265
|
+
return acc;
|
|
3266
|
+
}, []);
|
|
3267
|
+
return repos;
|
|
3062
3268
|
}
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3269
|
+
|
|
3270
|
+
// src/features/analysis/scm/constants.ts
|
|
3271
|
+
var MOBB_ICON_IMG = "https://app.mobb.ai/gh-action/Logo_Rounded_Icon.svg";
|
|
3272
|
+
|
|
3273
|
+
// src/constants.ts
|
|
3274
|
+
var debug = Debug("mobbdev:constants");
|
|
3275
|
+
var __dirname = path2.dirname(fileURLToPath(import.meta.url));
|
|
3276
|
+
dotenv.config({ path: path2.join(__dirname, "../.env") });
|
|
3277
|
+
var scmFriendlyText = {
|
|
3278
|
+
["Ado" /* Ado */]: "Azure DevOps",
|
|
3279
|
+
["Bitbucket" /* Bitbucket */]: "Bitbucket",
|
|
3280
|
+
["GitHub" /* GitHub */]: "GitGub",
|
|
3281
|
+
["GitLab" /* GitLab */]: "GitLab"
|
|
3282
|
+
};
|
|
3283
|
+
var SCANNERS = {
|
|
3284
|
+
Checkmarx: "checkmarx",
|
|
3285
|
+
Codeql: "codeql",
|
|
3286
|
+
Fortify: "fortify",
|
|
3287
|
+
Snyk: "snyk",
|
|
3288
|
+
Sonarqube: "sonarqube"
|
|
3289
|
+
};
|
|
3290
|
+
var SupportedScannersZ = z10.enum([SCANNERS.Checkmarx, SCANNERS.Snyk]);
|
|
3291
|
+
var envVariablesSchema = z10.object({
|
|
3292
|
+
WEB_APP_URL: z10.string(),
|
|
3293
|
+
API_URL: z10.string(),
|
|
3294
|
+
HASURA_ACCESS_KEY: z10.string(),
|
|
3295
|
+
LOCAL_GRAPHQL_ENDPOINT: z10.string()
|
|
3296
|
+
}).required();
|
|
3297
|
+
var envVariables = envVariablesSchema.parse(process.env);
|
|
3298
|
+
debug("config %o", envVariables);
|
|
3299
|
+
var mobbAscii = `
|
|
3300
|
+
..
|
|
3301
|
+
..........
|
|
3302
|
+
.................
|
|
3303
|
+
...........................
|
|
3304
|
+
..............................
|
|
3305
|
+
................................
|
|
3306
|
+
..................................
|
|
3307
|
+
....................................
|
|
3308
|
+
.....................................
|
|
3309
|
+
.............................................
|
|
3310
|
+
.................................................
|
|
3311
|
+
............................... .................
|
|
3312
|
+
.................................. ............
|
|
3313
|
+
.................. ............. ..........
|
|
3314
|
+
......... ........ ......... ......
|
|
3315
|
+
............... ....
|
|
3316
|
+
.... ..
|
|
3317
|
+
|
|
3318
|
+
. ...
|
|
3319
|
+
..............
|
|
3320
|
+
......................
|
|
3321
|
+
...........................
|
|
3322
|
+
................................
|
|
3323
|
+
......................................
|
|
3324
|
+
...............................
|
|
3325
|
+
.................
|
|
3326
|
+
`;
|
|
3327
|
+
var PROJECT_DEFAULT_NAME = "My first project";
|
|
3328
|
+
var WEB_APP_URL = envVariables.WEB_APP_URL;
|
|
3329
|
+
var API_URL = envVariables.API_URL;
|
|
3330
|
+
var HASURA_ACCESS_KEY = envVariables.HASURA_ACCESS_KEY;
|
|
3331
|
+
var LOCAL_GRAPHQL_ENDPOINT = envVariables.LOCAL_GRAPHQL_ENDPOINT;
|
|
3332
|
+
var errorMessages = {
|
|
3333
|
+
missingCxProjectName: `project name ${chalk.bold(
|
|
3334
|
+
"(--cx-project-name)"
|
|
3335
|
+
)} is needed if you're using checkmarx`,
|
|
3336
|
+
missingUrl: `url ${chalk.bold(
|
|
3337
|
+
"(--url)"
|
|
3338
|
+
)} is needed if you're adding an SCM token`,
|
|
3339
|
+
invalidScmType: `SCM type ${chalk.bold(
|
|
3340
|
+
"(--scm-type)"
|
|
3341
|
+
)} is invalid, please use one of: ${Object.values(ScmType).join(", ")}`,
|
|
3342
|
+
missingToken: `SCM token ${chalk.bold(
|
|
3343
|
+
"(--token)"
|
|
3344
|
+
)} is needed if you're adding an SCM token`
|
|
3345
|
+
};
|
|
3346
|
+
var progressMassages = {
|
|
3347
|
+
processingVulnerabilityReportSuccess: "\u2699\uFE0F Vulnerability report proccessed successfully",
|
|
3348
|
+
processingVulnerabilityReport: "\u2699\uFE0F Proccessing vulnerability report",
|
|
3349
|
+
processingVulnerabilityReportFailed: "\u2699\uFE0F Error Proccessing vulnerability report"
|
|
3350
|
+
};
|
|
3351
|
+
var VUL_REPORT_DIGEST_TIMEOUT_MS = 1e3 * 60 * 20;
|
|
3352
|
+
|
|
3353
|
+
// src/features/analysis/index.ts
|
|
3354
|
+
import crypto from "node:crypto";
|
|
3355
|
+
import fs3 from "node:fs";
|
|
3356
|
+
import os from "node:os";
|
|
3357
|
+
import path6 from "node:path";
|
|
3358
|
+
import { pipeline } from "node:stream/promises";
|
|
3359
|
+
|
|
3360
|
+
// src/generates/client_generates.ts
|
|
3361
|
+
var MeDocument = `
|
|
3362
|
+
query Me {
|
|
3363
|
+
me {
|
|
3364
|
+
id
|
|
3365
|
+
email
|
|
3366
|
+
scmConfigs {
|
|
3367
|
+
id
|
|
3368
|
+
orgId
|
|
3369
|
+
refreshToken
|
|
3370
|
+
scmType
|
|
3371
|
+
scmUrl
|
|
3372
|
+
scmUsername
|
|
3373
|
+
token
|
|
3374
|
+
tokenLastUpdate
|
|
3375
|
+
userId
|
|
3376
|
+
scmOrg
|
|
3377
|
+
isTokenAvailable
|
|
3378
|
+
}
|
|
3069
3379
|
}
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3380
|
+
}
|
|
3381
|
+
`;
|
|
3382
|
+
var GetOrgAndProjectIdDocument = `
|
|
3383
|
+
query getOrgAndProjectId($filters: organization_to_organization_role_bool_exp, $limit: Int) {
|
|
3384
|
+
organization_to_organization_role(
|
|
3385
|
+
where: $filters
|
|
3386
|
+
order_by: {organization: {createdOn: desc}}
|
|
3387
|
+
limit: $limit
|
|
3388
|
+
) {
|
|
3389
|
+
organization {
|
|
3390
|
+
id
|
|
3391
|
+
projects(order_by: {updatedAt: desc}) {
|
|
3392
|
+
id
|
|
3393
|
+
name
|
|
3080
3394
|
}
|
|
3081
|
-
case "public":
|
|
3082
|
-
return { authType };
|
|
3083
3395
|
}
|
|
3084
3396
|
}
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
return String(z7.number().parse(pullRequestRes.id));
|
|
3092
|
-
}
|
|
3093
|
-
async validateParams() {
|
|
3094
|
-
return validateBitbucketParams({
|
|
3095
|
-
bitbucketClient: this.bitbucketSdk,
|
|
3096
|
-
url: this.url
|
|
3097
|
-
});
|
|
3397
|
+
}
|
|
3398
|
+
`;
|
|
3399
|
+
var GetEncryptedApiTokenDocument = `
|
|
3400
|
+
query GetEncryptedApiToken($loginId: uuid!) {
|
|
3401
|
+
cli_login_by_pk(id: $loginId) {
|
|
3402
|
+
encryptedApiToken
|
|
3098
3403
|
}
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3404
|
+
}
|
|
3405
|
+
`;
|
|
3406
|
+
var FixReportStateDocument = `
|
|
3407
|
+
query FixReportState($id: uuid!) {
|
|
3408
|
+
fixReport_by_pk(id: $id) {
|
|
3409
|
+
state
|
|
3104
3410
|
}
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3411
|
+
}
|
|
3412
|
+
`;
|
|
3413
|
+
var GetVulnerabilityReportPathsDocument = `
|
|
3414
|
+
query GetVulnerabilityReportPaths($vulnerabilityReportId: uuid!) {
|
|
3415
|
+
vulnerability_report_path(
|
|
3416
|
+
where: {vulnerabilityReportId: {_eq: $vulnerabilityReportId}}
|
|
3417
|
+
) {
|
|
3418
|
+
path
|
|
3110
3419
|
}
|
|
3111
|
-
|
|
3112
|
-
|
|
3420
|
+
}
|
|
3421
|
+
`;
|
|
3422
|
+
var GetAnalysisDocument = `
|
|
3423
|
+
subscription getAnalysis($analysisId: uuid!) {
|
|
3424
|
+
analysis: fixReport_by_pk(id: $analysisId) {
|
|
3425
|
+
id
|
|
3426
|
+
state
|
|
3113
3427
|
}
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3428
|
+
}
|
|
3429
|
+
`;
|
|
3430
|
+
var GetAnalsyisDocument = `
|
|
3431
|
+
query getAnalsyis($analysisId: uuid!) {
|
|
3432
|
+
analysis: fixReport_by_pk(id: $analysisId) {
|
|
3433
|
+
id
|
|
3434
|
+
state
|
|
3435
|
+
repo {
|
|
3436
|
+
commitSha
|
|
3437
|
+
pullRequest
|
|
3438
|
+
}
|
|
3439
|
+
vulnerabilityReportId
|
|
3440
|
+
vulnerabilityReport {
|
|
3441
|
+
projectId
|
|
3442
|
+
project {
|
|
3443
|
+
organizationId
|
|
3444
|
+
}
|
|
3445
|
+
file {
|
|
3446
|
+
signedFile {
|
|
3447
|
+
url
|
|
3448
|
+
}
|
|
3129
3449
|
}
|
|
3130
3450
|
}
|
|
3131
3451
|
}
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3452
|
+
}
|
|
3453
|
+
`;
|
|
3454
|
+
var GetFixesDocument = `
|
|
3455
|
+
query getFixes($filters: fix_bool_exp!) {
|
|
3456
|
+
fixes: fix(where: $filters) {
|
|
3457
|
+
issueType
|
|
3458
|
+
id
|
|
3459
|
+
patchAndQuestions {
|
|
3460
|
+
__typename
|
|
3461
|
+
... on FixData {
|
|
3462
|
+
patch
|
|
3463
|
+
}
|
|
3141
3464
|
}
|
|
3142
|
-
return user.username;
|
|
3143
3465
|
}
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3466
|
+
}
|
|
3467
|
+
`;
|
|
3468
|
+
var GetVulByNodesMetadataDocument = `
|
|
3469
|
+
query getVulByNodesMetadata($filters: [vulnerability_report_issue_code_node_bool_exp!], $vulnerabilityReportId: uuid!) {
|
|
3470
|
+
vulnerabilityReportIssueCodeNodes: vulnerability_report_issue_code_node(
|
|
3471
|
+
order_by: {index: desc}
|
|
3472
|
+
where: {_or: $filters, vulnerabilityReportIssue: {fixId: {_is_null: false}, vulnerabilityReportId: {_eq: $vulnerabilityReportId}}}
|
|
3473
|
+
) {
|
|
3474
|
+
vulnerabilityReportIssueId
|
|
3475
|
+
path
|
|
3476
|
+
startLine
|
|
3477
|
+
vulnerabilityReportIssue {
|
|
3478
|
+
issueType
|
|
3479
|
+
fixId
|
|
3154
3480
|
}
|
|
3155
3481
|
}
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
this._validateAccessToken();
|
|
3162
|
-
const res = await this.bitbucketSdk.getUser();
|
|
3163
|
-
return z7.string().parse(res.username);
|
|
3164
|
-
}
|
|
3165
|
-
async getSubmitRequestStatus(_scmSubmitRequestId) {
|
|
3166
|
-
this._validateAccessTokenAndUrl();
|
|
3167
|
-
const pullRequestRes = await this.bitbucketSdk.getPullRequest({
|
|
3168
|
-
prNumber: Number(_scmSubmitRequestId),
|
|
3169
|
-
url: this.url
|
|
3170
|
-
});
|
|
3171
|
-
switch (pullRequestRes.state) {
|
|
3172
|
-
case "OPEN":
|
|
3173
|
-
return "open";
|
|
3174
|
-
case "MERGED":
|
|
3175
|
-
return "merged";
|
|
3176
|
-
case "DECLINED":
|
|
3177
|
-
return "closed";
|
|
3178
|
-
default:
|
|
3179
|
-
throw new Error(`unknown state ${pullRequestRes.state} `);
|
|
3482
|
+
fixablePrVuls: vulnerability_report_issue_aggregate(
|
|
3483
|
+
where: {fixId: {_is_null: false}, vulnerabilityReportId: {_eq: $vulnerabilityReportId}, codeNodes: {_or: $filters}}
|
|
3484
|
+
) {
|
|
3485
|
+
aggregate {
|
|
3486
|
+
count
|
|
3180
3487
|
}
|
|
3181
3488
|
}
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
}
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
this._validateUrl();
|
|
3196
|
-
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(this.url);
|
|
3197
|
-
return Promise.resolve(
|
|
3198
|
-
`https://bitbucket.org/${workspace}/${repoSlug}/pull-requests/${prNumber}`
|
|
3199
|
-
);
|
|
3200
|
-
}
|
|
3201
|
-
async refreshToken(params) {
|
|
3202
|
-
const getBitbucketTokenResponse = await getBitbucketToken({
|
|
3203
|
-
authType: "refresh_token",
|
|
3204
|
-
...params
|
|
3205
|
-
});
|
|
3206
|
-
return {
|
|
3207
|
-
accessToken: getBitbucketTokenResponse.access_token,
|
|
3208
|
-
refreshToken: getBitbucketTokenResponse.refresh_token
|
|
3209
|
-
};
|
|
3489
|
+
nonFixablePrVuls: vulnerability_report_issue_aggregate(
|
|
3490
|
+
where: {fixId: {_is_null: true}, vulnerabilityReportId: {_eq: $vulnerabilityReportId}, codeNodes: {_or: $filters}}
|
|
3491
|
+
) {
|
|
3492
|
+
aggregate {
|
|
3493
|
+
count
|
|
3494
|
+
}
|
|
3495
|
+
}
|
|
3496
|
+
totalScanVulnerabilities: vulnerability_report_issue_aggregate(
|
|
3497
|
+
where: {vulnerabilityReportId: {_eq: $vulnerabilityReportId}}
|
|
3498
|
+
) {
|
|
3499
|
+
aggregate {
|
|
3500
|
+
count
|
|
3501
|
+
}
|
|
3210
3502
|
}
|
|
3211
|
-
};
|
|
3212
|
-
|
|
3213
|
-
// src/features/analysis/scm/ado/validation.ts
|
|
3214
|
-
import { z as z8 } from "zod";
|
|
3215
|
-
var ValidPullRequestStatusZ = z8.union([
|
|
3216
|
-
z8.literal(1 /* Active */),
|
|
3217
|
-
z8.literal(2 /* Abandoned */),
|
|
3218
|
-
z8.literal(3 /* Completed */)
|
|
3219
|
-
]);
|
|
3220
|
-
var AdoAuthResultZ = z8.object({
|
|
3221
|
-
access_token: z8.string().min(1),
|
|
3222
|
-
token_type: z8.string().min(1),
|
|
3223
|
-
refresh_token: z8.string().min(1)
|
|
3224
|
-
});
|
|
3225
|
-
var profileZ = z8.object({
|
|
3226
|
-
displayName: z8.string(),
|
|
3227
|
-
publicAlias: z8.string().min(1),
|
|
3228
|
-
emailAddress: z8.string(),
|
|
3229
|
-
coreRevision: z8.number(),
|
|
3230
|
-
timeStamp: z8.string(),
|
|
3231
|
-
id: z8.string(),
|
|
3232
|
-
revision: z8.number()
|
|
3233
|
-
});
|
|
3234
|
-
var accountsZ = z8.object({
|
|
3235
|
-
count: z8.number(),
|
|
3236
|
-
value: z8.array(
|
|
3237
|
-
z8.object({
|
|
3238
|
-
accountId: z8.string(),
|
|
3239
|
-
accountUri: z8.string(),
|
|
3240
|
-
accountName: z8.string()
|
|
3241
|
-
})
|
|
3242
|
-
)
|
|
3243
|
-
});
|
|
3244
|
-
|
|
3245
|
-
// src/features/analysis/scm/ado/utils.ts
|
|
3246
|
-
function _getPublicAdoClient({
|
|
3247
|
-
orgName,
|
|
3248
|
-
origin: origin2
|
|
3249
|
-
}) {
|
|
3250
|
-
const orgUrl = `${origin2}/${orgName}`;
|
|
3251
|
-
const authHandler = api.getPersonalAccessTokenHandler("");
|
|
3252
|
-
authHandler.canHandleAuthentication = () => false;
|
|
3253
|
-
authHandler.prepareRequest = (_options) => {
|
|
3254
|
-
return;
|
|
3255
|
-
};
|
|
3256
|
-
const connection = new api.WebApi(orgUrl, authHandler);
|
|
3257
|
-
return connection;
|
|
3258
|
-
}
|
|
3259
|
-
function removeTrailingSlash2(str) {
|
|
3260
|
-
return str.trim().replace(/\/+$/, "");
|
|
3261
3503
|
}
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3504
|
+
`;
|
|
3505
|
+
var UpdateScmTokenDocument = `
|
|
3506
|
+
mutation updateScmToken($scmType: String!, $url: String!, $token: String!, $org: String, $refreshToken: String) {
|
|
3507
|
+
updateScmToken(
|
|
3508
|
+
scmType: $scmType
|
|
3509
|
+
url: $url
|
|
3510
|
+
token: $token
|
|
3511
|
+
org: $org
|
|
3512
|
+
refreshToken: $refreshToken
|
|
3513
|
+
) {
|
|
3514
|
+
__typename
|
|
3515
|
+
... on ScmAccessTokenUpdateSuccess {
|
|
3516
|
+
token
|
|
3517
|
+
}
|
|
3518
|
+
... on InvalidScmTypeError {
|
|
3519
|
+
status
|
|
3520
|
+
error
|
|
3521
|
+
}
|
|
3522
|
+
... on BadScmCredentials {
|
|
3523
|
+
status
|
|
3524
|
+
error
|
|
3525
|
+
}
|
|
3268
3526
|
}
|
|
3269
|
-
const {
|
|
3270
|
-
organization,
|
|
3271
|
-
repoName,
|
|
3272
|
-
projectName,
|
|
3273
|
-
projectPath,
|
|
3274
|
-
pathElements,
|
|
3275
|
-
hostname,
|
|
3276
|
-
protocol
|
|
3277
|
-
} = parsingResult;
|
|
3278
|
-
return {
|
|
3279
|
-
owner: decodeURI(organization),
|
|
3280
|
-
repo: decodeURI(repoName),
|
|
3281
|
-
projectName: projectName ? decodeURI(projectName) : void 0,
|
|
3282
|
-
projectPath,
|
|
3283
|
-
pathElements,
|
|
3284
|
-
origin: `${protocol}//${hostname}`
|
|
3285
|
-
};
|
|
3286
3527
|
}
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3528
|
+
`;
|
|
3529
|
+
var UploadS3BucketInfoDocument = `
|
|
3530
|
+
mutation uploadS3BucketInfo($fileName: String!) {
|
|
3531
|
+
uploadS3BucketInfo(fileName: $fileName) {
|
|
3532
|
+
status
|
|
3533
|
+
error
|
|
3534
|
+
reportUploadInfo: uploadInfo {
|
|
3535
|
+
url
|
|
3536
|
+
fixReportId
|
|
3537
|
+
uploadFieldsJSON
|
|
3538
|
+
uploadKey
|
|
3539
|
+
}
|
|
3540
|
+
repoUploadInfo {
|
|
3541
|
+
url
|
|
3542
|
+
fixReportId
|
|
3543
|
+
uploadFieldsJSON
|
|
3544
|
+
uploadKey
|
|
3545
|
+
}
|
|
3298
3546
|
}
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3547
|
+
}
|
|
3548
|
+
`;
|
|
3549
|
+
var DigestVulnerabilityReportDocument = `
|
|
3550
|
+
mutation DigestVulnerabilityReport($vulnerabilityReportFileName: String!, $fixReportId: String!, $projectId: String!, $scanSource: String!) {
|
|
3551
|
+
digestVulnerabilityReport(
|
|
3552
|
+
fixReportId: $fixReportId
|
|
3553
|
+
vulnerabilityReportFileName: $vulnerabilityReportFileName
|
|
3554
|
+
projectId: $projectId
|
|
3555
|
+
scanSource: $scanSource
|
|
3556
|
+
) {
|
|
3557
|
+
__typename
|
|
3558
|
+
... on VulnerabilityReport {
|
|
3559
|
+
vulnerabilityReportId
|
|
3560
|
+
fixReportId
|
|
3561
|
+
}
|
|
3562
|
+
... on RabbitSendError {
|
|
3563
|
+
status
|
|
3564
|
+
error
|
|
3565
|
+
}
|
|
3566
|
+
... on ReportValidationError {
|
|
3567
|
+
status
|
|
3568
|
+
error
|
|
3569
|
+
}
|
|
3570
|
+
... on ReferenceNotFoundError {
|
|
3571
|
+
status
|
|
3572
|
+
error
|
|
3308
3573
|
}
|
|
3309
|
-
throw new InvalidRepoUrlError("ADO URL is null");
|
|
3310
3574
|
}
|
|
3311
|
-
return {
|
|
3312
|
-
org: tokenOrg,
|
|
3313
|
-
origin: DEFUALT_ADO_ORIGIN
|
|
3314
|
-
};
|
|
3315
3575
|
}
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3576
|
+
`;
|
|
3577
|
+
var SubmitVulnerabilityReportDocument = `
|
|
3578
|
+
mutation SubmitVulnerabilityReport($fixReportId: String!, $repoUrl: String!, $reference: String!, $projectId: String!, $scanSource: String!, $sha: String, $experimentalEnabled: Boolean, $vulnerabilityReportFileName: String, $pullRequest: Int) {
|
|
3579
|
+
submitVulnerabilityReport(
|
|
3580
|
+
fixReportId: $fixReportId
|
|
3581
|
+
repoUrl: $repoUrl
|
|
3582
|
+
reference: $reference
|
|
3583
|
+
sha: $sha
|
|
3584
|
+
experimentalEnabled: $experimentalEnabled
|
|
3585
|
+
pullRequest: $pullRequest
|
|
3586
|
+
projectId: $projectId
|
|
3587
|
+
vulnerabilityReportFileName: $vulnerabilityReportFileName
|
|
3588
|
+
scanSource: $scanSource
|
|
3589
|
+
) {
|
|
3590
|
+
__typename
|
|
3591
|
+
... on VulnerabilityReport {
|
|
3592
|
+
vulnerabilityReportId
|
|
3593
|
+
fixReportId
|
|
3594
|
+
}
|
|
3321
3595
|
}
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3596
|
+
}
|
|
3597
|
+
`;
|
|
3598
|
+
var CreateCommunityUserDocument = `
|
|
3599
|
+
mutation CreateCommunityUser {
|
|
3600
|
+
initOrganizationAndProject {
|
|
3601
|
+
__typename
|
|
3602
|
+
... on InitOrganizationAndProjectGoodResponse {
|
|
3603
|
+
projectId
|
|
3604
|
+
userId
|
|
3605
|
+
organizationId
|
|
3606
|
+
}
|
|
3607
|
+
... on UserAlreadyInProjectError {
|
|
3608
|
+
error
|
|
3609
|
+
status
|
|
3328
3610
|
}
|
|
3329
|
-
const connection2 = new api.WebApi(
|
|
3330
|
-
orgUrl,
|
|
3331
|
-
api.getBearerHandler(params.accessToken),
|
|
3332
|
-
{}
|
|
3333
|
-
);
|
|
3334
|
-
return connection2;
|
|
3335
3611
|
}
|
|
3336
|
-
const authHandler = api.getPersonalAccessTokenHandler(params.accessToken);
|
|
3337
|
-
const isBroker = BROKERED_HOSTS.includes(new URL(orgUrl).origin);
|
|
3338
|
-
const connection = new api.WebApi(
|
|
3339
|
-
orgUrl,
|
|
3340
|
-
authHandler,
|
|
3341
|
-
isBroker ? {
|
|
3342
|
-
proxy: {
|
|
3343
|
-
proxyUrl: GIT_PROXY_HOST
|
|
3344
|
-
},
|
|
3345
|
-
ignoreSslError: true
|
|
3346
|
-
} : void 0
|
|
3347
|
-
);
|
|
3348
|
-
return connection;
|
|
3349
3612
|
}
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3613
|
+
`;
|
|
3614
|
+
var CreateCliLoginDocument = `
|
|
3615
|
+
mutation CreateCliLogin($publicKey: String!) {
|
|
3616
|
+
insert_cli_login_one(object: {publicKey: $publicKey}) {
|
|
3617
|
+
id
|
|
3353
3618
|
}
|
|
3354
|
-
|
|
3355
|
-
|
|
3619
|
+
}
|
|
3620
|
+
`;
|
|
3621
|
+
var PerformCliLoginDocument = `
|
|
3622
|
+
mutation performCliLogin($loginId: String!) {
|
|
3623
|
+
performCliLogin(loginId: $loginId) {
|
|
3624
|
+
status
|
|
3356
3625
|
}
|
|
3357
|
-
return { type: "PAT" /* PAT */, accessToken: token };
|
|
3358
3626
|
}
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
tokenOrg,
|
|
3365
|
-
adoTokenInfo
|
|
3366
|
-
});
|
|
3367
|
-
switch (adoTokenInfo.type) {
|
|
3368
|
-
case "NONE" /* NONE */:
|
|
3369
|
-
return {
|
|
3370
|
-
tokenType: "NONE" /* NONE */,
|
|
3371
|
-
origin: origin2,
|
|
3372
|
-
orgName: org.toLowerCase()
|
|
3373
|
-
};
|
|
3374
|
-
case "OAUTH" /* OAUTH */: {
|
|
3375
|
-
return {
|
|
3376
|
-
tokenType: "OAUTH" /* OAUTH */,
|
|
3377
|
-
accessToken: adoTokenInfo.accessToken,
|
|
3378
|
-
origin: origin2,
|
|
3379
|
-
orgName: org.toLowerCase()
|
|
3380
|
-
};
|
|
3381
|
-
}
|
|
3382
|
-
case "PAT" /* PAT */: {
|
|
3383
|
-
return {
|
|
3384
|
-
tokenType: "PAT" /* PAT */,
|
|
3385
|
-
accessToken: adoTokenInfo.accessToken,
|
|
3386
|
-
patTokenOrg: z9.string().parse(tokenOrg).toLowerCase(),
|
|
3387
|
-
origin: origin2,
|
|
3388
|
-
orgName: org.toLowerCase()
|
|
3389
|
-
};
|
|
3390
|
-
}
|
|
3627
|
+
`;
|
|
3628
|
+
var CreateProjectDocument = `
|
|
3629
|
+
mutation CreateProject($organizationId: String!, $projectName: String!) {
|
|
3630
|
+
createProject(organizationId: $organizationId, projectName: $projectName) {
|
|
3631
|
+
projectId
|
|
3391
3632
|
}
|
|
3392
3633
|
}
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
console.log("adoValidateParams error", e);
|
|
3405
|
-
const error = e;
|
|
3406
|
-
const code = error.code || error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
|
|
3407
|
-
const description = error.description || `${e}`;
|
|
3408
|
-
if (code === 401 || code === 403 || description.includes("401") || description.includes("403")) {
|
|
3409
|
-
throw new InvalidAccessTokenError(`invalid ADO access token`);
|
|
3634
|
+
`;
|
|
3635
|
+
var ValidateRepoUrlDocument = `
|
|
3636
|
+
query validateRepoUrl($repoUrl: String!) {
|
|
3637
|
+
validateRepoUrl(repoUrl: $repoUrl) {
|
|
3638
|
+
__typename
|
|
3639
|
+
... on RepoValidationSuccess {
|
|
3640
|
+
status
|
|
3641
|
+
defaultBranch
|
|
3642
|
+
defaultBranchLastModified
|
|
3643
|
+
defaultBranchSha
|
|
3644
|
+
scmType
|
|
3410
3645
|
}
|
|
3411
|
-
|
|
3412
|
-
|
|
3646
|
+
... on RepoUnreachableError {
|
|
3647
|
+
status
|
|
3648
|
+
error
|
|
3649
|
+
scmType
|
|
3650
|
+
}
|
|
3651
|
+
... on BadScmCredentials {
|
|
3652
|
+
status
|
|
3653
|
+
error
|
|
3654
|
+
scmType
|
|
3413
3655
|
}
|
|
3414
|
-
throw e;
|
|
3415
3656
|
}
|
|
3416
3657
|
}
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
{
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
}
|
|
3658
|
+
`;
|
|
3659
|
+
var GitReferenceDocument = `
|
|
3660
|
+
query gitReference($repoUrl: String!, $reference: String!) {
|
|
3661
|
+
gitReference(repoUrl: $repoUrl, reference: $reference) {
|
|
3662
|
+
__typename
|
|
3663
|
+
... on GitReferenceData {
|
|
3664
|
+
status
|
|
3665
|
+
sha
|
|
3666
|
+
date
|
|
3427
3667
|
}
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
const accountsRes = await fetch(
|
|
3432
|
-
`https://app.vssps.visualstudio.com/_apis/accounts?memberId=${profile.publicAlias}&api-version=6.0`,
|
|
3433
|
-
{
|
|
3434
|
-
method: "GET",
|
|
3435
|
-
headers: {
|
|
3436
|
-
Authorization: `Bearer ${oauthToken}`
|
|
3437
|
-
}
|
|
3668
|
+
... on ReferenceNotFoundError {
|
|
3669
|
+
status
|
|
3670
|
+
error
|
|
3438
3671
|
}
|
|
3439
|
-
|
|
3440
|
-
const accountsJson = await accountsRes.json();
|
|
3441
|
-
const accounts = accountsZ.parse(accountsJson);
|
|
3442
|
-
const orgs = accounts.value.map((account) => account.accountName).filter((value, index, array) => array.indexOf(value) === index);
|
|
3443
|
-
return orgs;
|
|
3672
|
+
}
|
|
3444
3673
|
}
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
const api2 = await getAdoApiClient(params);
|
|
3674
|
+
`;
|
|
3675
|
+
var defaultWrapper = (action, _operationName, _operationType, _variables) => action();
|
|
3676
|
+
function getSdk(client, withWrapper = defaultWrapper) {
|
|
3449
3677
|
return {
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3453
|
-
const git = await api2.getGitApi();
|
|
3454
|
-
const branches = await git.getBranches(repo, projectName);
|
|
3455
|
-
if (!branches || branches.length === 0) {
|
|
3456
|
-
throw new InvalidRepoUrlError("no branches");
|
|
3457
|
-
}
|
|
3458
|
-
return true;
|
|
3459
|
-
} catch (e) {
|
|
3460
|
-
return false;
|
|
3461
|
-
}
|
|
3678
|
+
Me(variables, requestHeaders) {
|
|
3679
|
+
return withWrapper((wrappedRequestHeaders) => client.request(MeDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "Me", "query", variables);
|
|
3462
3680
|
},
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
prNumber
|
|
3466
|
-
}) {
|
|
3467
|
-
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3468
|
-
const git = await api2.getGitApi();
|
|
3469
|
-
const res = await git.getPullRequest(repo, prNumber, projectName);
|
|
3470
|
-
const parsedPullRequestStatus = ValidPullRequestStatusZ.safeParse(
|
|
3471
|
-
res.status
|
|
3472
|
-
);
|
|
3473
|
-
if (!parsedPullRequestStatus.success) {
|
|
3474
|
-
throw new Error("bad pr status for ADO");
|
|
3475
|
-
}
|
|
3476
|
-
return parsedPullRequestStatus.data;
|
|
3681
|
+
getOrgAndProjectId(variables, requestHeaders) {
|
|
3682
|
+
return withWrapper((wrappedRequestHeaders) => client.request(GetOrgAndProjectIdDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getOrgAndProjectId", "query", variables);
|
|
3477
3683
|
},
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
branch
|
|
3481
|
-
}) {
|
|
3482
|
-
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3483
|
-
const git = await api2.getGitApi();
|
|
3484
|
-
try {
|
|
3485
|
-
const branchStatus = await git.getBranch(repo, branch, projectName);
|
|
3486
|
-
if (!branchStatus || !branchStatus.commit) {
|
|
3487
|
-
throw new InvalidRepoUrlError("no branch status");
|
|
3488
|
-
}
|
|
3489
|
-
return branchStatus.name === branch;
|
|
3490
|
-
} catch (e) {
|
|
3491
|
-
return false;
|
|
3492
|
-
}
|
|
3684
|
+
GetEncryptedApiToken(variables, requestHeaders) {
|
|
3685
|
+
return withWrapper((wrappedRequestHeaders) => client.request(GetEncryptedApiTokenDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "GetEncryptedApiToken", "query", variables);
|
|
3493
3686
|
},
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
const git = await api2.getGitApi();
|
|
3497
|
-
const getRepositoryRes = await git.getRepository(
|
|
3498
|
-
decodeURI(repo),
|
|
3499
|
-
projectName ? decodeURI(projectName) : void 0
|
|
3500
|
-
);
|
|
3501
|
-
return `${getRepositoryRes.webUrl}/pullrequest/${prNumber}`;
|
|
3687
|
+
FixReportState(variables, requestHeaders) {
|
|
3688
|
+
return withWrapper((wrappedRequestHeaders) => client.request(FixReportStateDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "FixReportState", "query", variables);
|
|
3502
3689
|
},
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
branch
|
|
3506
|
-
}) {
|
|
3507
|
-
const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3508
|
-
const url = new URL(repoUrl);
|
|
3509
|
-
const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
|
|
3510
|
-
return `${origin2}/${owner}/${projectName}/_apis/git/repositories/${repo}/items/items?path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
|
|
3690
|
+
GetVulnerabilityReportPaths(variables, requestHeaders) {
|
|
3691
|
+
return withWrapper((wrappedRequestHeaders) => client.request(GetVulnerabilityReportPathsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "GetVulnerabilityReportPaths", "query", variables);
|
|
3511
3692
|
},
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
const git = await api2.getGitApi();
|
|
3515
|
-
try {
|
|
3516
|
-
const res = await git.getBranches(repo, projectName);
|
|
3517
|
-
res.sort((a, b) => {
|
|
3518
|
-
if (!a.commit?.committer?.date || !b.commit?.committer?.date) {
|
|
3519
|
-
return 0;
|
|
3520
|
-
}
|
|
3521
|
-
return b.commit?.committer?.date.getTime() - a.commit?.committer?.date.getTime();
|
|
3522
|
-
});
|
|
3523
|
-
return res.reduce((acc, branch) => {
|
|
3524
|
-
if (!branch.name) {
|
|
3525
|
-
return acc;
|
|
3526
|
-
}
|
|
3527
|
-
acc.push(branch.name);
|
|
3528
|
-
return acc;
|
|
3529
|
-
}, []);
|
|
3530
|
-
} catch (e) {
|
|
3531
|
-
return [];
|
|
3532
|
-
}
|
|
3693
|
+
getAnalysis(variables, requestHeaders) {
|
|
3694
|
+
return withWrapper((wrappedRequestHeaders) => client.request(GetAnalysisDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getAnalysis", "subscription", variables);
|
|
3533
3695
|
},
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3537
|
-
const git = await api2.getGitApi();
|
|
3538
|
-
const res = await git.createPullRequest(
|
|
3539
|
-
{
|
|
3540
|
-
sourceRefName: `refs/heads/${sourceBranchName}`,
|
|
3541
|
-
targetRefName: `refs/heads/${targetBranchName}`,
|
|
3542
|
-
title,
|
|
3543
|
-
description: body
|
|
3544
|
-
},
|
|
3545
|
-
repo,
|
|
3546
|
-
projectName
|
|
3547
|
-
);
|
|
3548
|
-
return res.pullRequestId;
|
|
3696
|
+
getAnalsyis(variables, requestHeaders) {
|
|
3697
|
+
return withWrapper((wrappedRequestHeaders) => client.request(GetAnalsyisDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getAnalsyis", "query", variables);
|
|
3549
3698
|
},
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
}) {
|
|
3553
|
-
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3554
|
-
const git = await api2.getGitApi();
|
|
3555
|
-
const getRepositoryRes = await git.getRepository(
|
|
3556
|
-
decodeURI(repo),
|
|
3557
|
-
projectName ? decodeURI(projectName) : void 0
|
|
3558
|
-
);
|
|
3559
|
-
if (!getRepositoryRes?.defaultBranch) {
|
|
3560
|
-
throw new InvalidRepoUrlError("no default branch");
|
|
3561
|
-
}
|
|
3562
|
-
return getRepositoryRes.defaultBranch.replace("refs/heads/", "");
|
|
3699
|
+
getFixes(variables, requestHeaders) {
|
|
3700
|
+
return withWrapper((wrappedRequestHeaders) => client.request(GetFixesDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getFixes", "query", variables);
|
|
3563
3701
|
},
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3570
|
-
if (!projectName) {
|
|
3571
|
-
throw new InvalidUrlPatternError("no project name");
|
|
3572
|
-
}
|
|
3573
|
-
const git = await api2.getGitApi();
|
|
3574
|
-
const results = await Promise.allSettled([
|
|
3575
|
-
(async () => {
|
|
3576
|
-
const res = await git.getBranch(repo, ref, projectName);
|
|
3577
|
-
if (!res.commit || !res.commit.commitId) {
|
|
3578
|
-
throw new InvalidRepoUrlError("no commit on branch");
|
|
3579
|
-
}
|
|
3580
|
-
return {
|
|
3581
|
-
sha: res.commit.commitId,
|
|
3582
|
-
type: "BRANCH" /* BRANCH */,
|
|
3583
|
-
date: res.commit.committer?.date || /* @__PURE__ */ new Date()
|
|
3584
|
-
};
|
|
3585
|
-
})(),
|
|
3586
|
-
(async () => {
|
|
3587
|
-
const res = await git.getCommits(
|
|
3588
|
-
repo,
|
|
3589
|
-
{
|
|
3590
|
-
fromCommitId: ref,
|
|
3591
|
-
toCommitId: ref,
|
|
3592
|
-
$top: 1
|
|
3593
|
-
},
|
|
3594
|
-
projectName
|
|
3595
|
-
);
|
|
3596
|
-
const commit = res[0];
|
|
3597
|
-
if (!commit || !commit.commitId) {
|
|
3598
|
-
throw new Error("no commit");
|
|
3599
|
-
}
|
|
3600
|
-
return {
|
|
3601
|
-
sha: commit.commitId,
|
|
3602
|
-
type: "COMMIT" /* COMMIT */,
|
|
3603
|
-
date: commit.committer?.date || /* @__PURE__ */ new Date()
|
|
3604
|
-
};
|
|
3605
|
-
})(),
|
|
3606
|
-
(async () => {
|
|
3607
|
-
const res = await git.getRefs(repo, projectName, `tags/${ref}`);
|
|
3608
|
-
if (!res[0] || !res[0].objectId) {
|
|
3609
|
-
throw new Error("no tag ref");
|
|
3610
|
-
}
|
|
3611
|
-
let objectId = res[0].objectId;
|
|
3612
|
-
try {
|
|
3613
|
-
const tag = await git.getAnnotatedTag(projectName, repo, objectId);
|
|
3614
|
-
if (tag.taggedObject?.objectId) {
|
|
3615
|
-
objectId = tag.taggedObject.objectId;
|
|
3616
|
-
}
|
|
3617
|
-
} catch (e) {
|
|
3618
|
-
}
|
|
3619
|
-
const commitRes2 = await git.getCommits(
|
|
3620
|
-
repo,
|
|
3621
|
-
{
|
|
3622
|
-
fromCommitId: objectId,
|
|
3623
|
-
toCommitId: objectId,
|
|
3624
|
-
$top: 1
|
|
3625
|
-
},
|
|
3626
|
-
projectName
|
|
3627
|
-
);
|
|
3628
|
-
const commit = commitRes2[0];
|
|
3629
|
-
if (!commit) {
|
|
3630
|
-
throw new Error("no commit");
|
|
3631
|
-
}
|
|
3632
|
-
return {
|
|
3633
|
-
sha: objectId,
|
|
3634
|
-
type: "TAG" /* TAG */,
|
|
3635
|
-
date: commit.committer?.date || /* @__PURE__ */ new Date()
|
|
3636
|
-
};
|
|
3637
|
-
})()
|
|
3638
|
-
]);
|
|
3639
|
-
const [branchRes, commitRes, tagRes] = results;
|
|
3640
|
-
if (tagRes.status === "fulfilled") {
|
|
3641
|
-
return tagRes.value;
|
|
3642
|
-
}
|
|
3643
|
-
if (branchRes.status === "fulfilled") {
|
|
3644
|
-
return branchRes.value;
|
|
3645
|
-
}
|
|
3646
|
-
if (commitRes.status === "fulfilled") {
|
|
3647
|
-
return commitRes.value;
|
|
3648
|
-
}
|
|
3649
|
-
throw new RefNotFoundError(`ref: ${ref} does not exist`);
|
|
3702
|
+
getVulByNodesMetadata(variables, requestHeaders) {
|
|
3703
|
+
return withWrapper((wrappedRequestHeaders) => client.request(GetVulByNodesMetadataDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "getVulByNodesMetadata", "query", variables);
|
|
3704
|
+
},
|
|
3705
|
+
updateScmToken(variables, requestHeaders) {
|
|
3706
|
+
return withWrapper((wrappedRequestHeaders) => client.request(UpdateScmTokenDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "updateScmToken", "mutation", variables);
|
|
3650
3707
|
},
|
|
3651
|
-
|
|
3652
|
-
return
|
|
3708
|
+
uploadS3BucketInfo(variables, requestHeaders) {
|
|
3709
|
+
return withWrapper((wrappedRequestHeaders) => client.request(UploadS3BucketInfoDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "uploadS3BucketInfo", "mutation", variables);
|
|
3710
|
+
},
|
|
3711
|
+
DigestVulnerabilityReport(variables, requestHeaders) {
|
|
3712
|
+
return withWrapper((wrappedRequestHeaders) => client.request(DigestVulnerabilityReportDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "DigestVulnerabilityReport", "mutation", variables);
|
|
3713
|
+
},
|
|
3714
|
+
SubmitVulnerabilityReport(variables, requestHeaders) {
|
|
3715
|
+
return withWrapper((wrappedRequestHeaders) => client.request(SubmitVulnerabilityReportDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "SubmitVulnerabilityReport", "mutation", variables);
|
|
3716
|
+
},
|
|
3717
|
+
CreateCommunityUser(variables, requestHeaders) {
|
|
3718
|
+
return withWrapper((wrappedRequestHeaders) => client.request(CreateCommunityUserDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CreateCommunityUser", "mutation", variables);
|
|
3719
|
+
},
|
|
3720
|
+
CreateCliLogin(variables, requestHeaders) {
|
|
3721
|
+
return withWrapper((wrappedRequestHeaders) => client.request(CreateCliLoginDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CreateCliLogin", "mutation", variables);
|
|
3722
|
+
},
|
|
3723
|
+
performCliLogin(variables, requestHeaders) {
|
|
3724
|
+
return withWrapper((wrappedRequestHeaders) => client.request(PerformCliLoginDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "performCliLogin", "mutation", variables);
|
|
3725
|
+
},
|
|
3726
|
+
CreateProject(variables, requestHeaders) {
|
|
3727
|
+
return withWrapper((wrappedRequestHeaders) => client.request(CreateProjectDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "CreateProject", "mutation", variables);
|
|
3728
|
+
},
|
|
3729
|
+
validateRepoUrl(variables, requestHeaders) {
|
|
3730
|
+
return withWrapper((wrappedRequestHeaders) => client.request(ValidateRepoUrlDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "validateRepoUrl", "query", variables);
|
|
3731
|
+
},
|
|
3732
|
+
gitReference(variables, requestHeaders) {
|
|
3733
|
+
return withWrapper((wrappedRequestHeaders) => client.request(GitReferenceDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), "gitReference", "query", variables);
|
|
3653
3734
|
}
|
|
3654
3735
|
};
|
|
3655
3736
|
}
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
const orgApi = await getAdoApiClient({
|
|
3677
|
-
...await getAdoClientParams({
|
|
3678
|
-
accessToken,
|
|
3679
|
-
tokenOrg: tokenOrg || org,
|
|
3680
|
-
url: void 0
|
|
3681
|
-
}),
|
|
3682
|
-
orgName: org
|
|
3683
|
-
});
|
|
3684
|
-
const gitOrg = await orgApi.getGitApi();
|
|
3685
|
-
const orgRepos = await gitOrg.getRepositories();
|
|
3686
|
-
const repoInfoList = (await Promise.allSettled(
|
|
3687
|
-
orgRepos.map(async (repo) => {
|
|
3688
|
-
if (!repo.name || !repo.remoteUrl || !repo.defaultBranch) {
|
|
3689
|
-
throw new InvalidRepoUrlError("bad repo");
|
|
3690
|
-
}
|
|
3691
|
-
const branch = await gitOrg.getBranch(
|
|
3692
|
-
repo.name,
|
|
3693
|
-
repo.defaultBranch.replace(/^refs\/heads\//, ""),
|
|
3694
|
-
repo.project?.name
|
|
3695
|
-
);
|
|
3696
|
-
return {
|
|
3697
|
-
repoName: repo.name,
|
|
3698
|
-
repoUrl: repo.remoteUrl.replace(
|
|
3699
|
-
/^[hH][tT][tT][pP][sS]:\/\/[^/]+@/,
|
|
3700
|
-
"https://"
|
|
3701
|
-
),
|
|
3702
|
-
repoOwner: org,
|
|
3703
|
-
repoIsPublic: repo.project?.visibility === 2 /* Public */,
|
|
3704
|
-
repoLanguages: [],
|
|
3705
|
-
repoUpdatedAt: branch.commit?.committer?.date?.toDateString() || repo.project?.lastUpdateTime?.toDateString() || (/* @__PURE__ */ new Date()).toDateString()
|
|
3706
|
-
};
|
|
3707
|
-
})
|
|
3708
|
-
)).reduce((acc, res) => {
|
|
3709
|
-
if (res.status === "fulfilled") {
|
|
3710
|
-
acc.push(res.value);
|
|
3711
|
-
}
|
|
3712
|
-
return acc;
|
|
3713
|
-
}, []);
|
|
3714
|
-
return repoInfoList;
|
|
3715
|
-
})
|
|
3716
|
-
)).reduce((acc, res) => {
|
|
3717
|
-
if (res.status === "fulfilled") {
|
|
3718
|
-
return acc.concat(res.value);
|
|
3719
|
-
}
|
|
3720
|
-
return acc;
|
|
3721
|
-
}, []);
|
|
3722
|
-
return repos;
|
|
3737
|
+
|
|
3738
|
+
// src/utils/index.ts
|
|
3739
|
+
var utils_exports = {};
|
|
3740
|
+
__export(utils_exports, {
|
|
3741
|
+
CliError: () => CliError,
|
|
3742
|
+
Spinner: () => Spinner,
|
|
3743
|
+
getDirName: () => getDirName,
|
|
3744
|
+
getTopLevelDirName: () => getTopLevelDirName,
|
|
3745
|
+
keypress: () => keypress,
|
|
3746
|
+
sleep: () => sleep
|
|
3747
|
+
});
|
|
3748
|
+
|
|
3749
|
+
// src/utils/dirname.ts
|
|
3750
|
+
import path3 from "node:path";
|
|
3751
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
3752
|
+
function getDirName() {
|
|
3753
|
+
return path3.dirname(fileURLToPath2(import.meta.url));
|
|
3754
|
+
}
|
|
3755
|
+
function getTopLevelDirName(fullPath) {
|
|
3756
|
+
return path3.parse(fullPath).name;
|
|
3723
3757
|
}
|
|
3724
3758
|
|
|
3725
|
-
// src/
|
|
3726
|
-
|
|
3759
|
+
// src/utils/keypress.ts
|
|
3760
|
+
import readline from "node:readline";
|
|
3761
|
+
async function keypress() {
|
|
3762
|
+
const rl = readline.createInterface({
|
|
3763
|
+
input: process.stdin,
|
|
3764
|
+
output: process.stdout
|
|
3765
|
+
});
|
|
3766
|
+
return new Promise((resolve) => {
|
|
3767
|
+
rl.question("", (answer) => {
|
|
3768
|
+
rl.close();
|
|
3769
|
+
process.stderr.moveCursor(0, -1);
|
|
3770
|
+
process.stderr.clearLine(1);
|
|
3771
|
+
resolve(answer);
|
|
3772
|
+
});
|
|
3773
|
+
});
|
|
3774
|
+
}
|
|
3775
|
+
|
|
3776
|
+
// src/utils/spinner.ts
|
|
3777
|
+
import {
|
|
3778
|
+
createSpinner as _createSpinner
|
|
3779
|
+
} from "nanospinner";
|
|
3780
|
+
var mockSpinner = {
|
|
3781
|
+
success: () => mockSpinner,
|
|
3782
|
+
error: () => mockSpinner,
|
|
3783
|
+
warn: () => mockSpinner,
|
|
3784
|
+
stop: () => mockSpinner,
|
|
3785
|
+
start: () => mockSpinner,
|
|
3786
|
+
update: () => mockSpinner,
|
|
3787
|
+
reset: () => mockSpinner,
|
|
3788
|
+
clear: () => mockSpinner,
|
|
3789
|
+
spin: () => mockSpinner
|
|
3790
|
+
};
|
|
3791
|
+
function Spinner({ ci = false } = {}) {
|
|
3792
|
+
return {
|
|
3793
|
+
createSpinner: (text, options) => ci ? mockSpinner : _createSpinner(text, options)
|
|
3794
|
+
};
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
// src/utils/index.ts
|
|
3798
|
+
var sleep = (ms = 2e3) => new Promise((r) => setTimeout(r, ms));
|
|
3799
|
+
var CliError = class extends Error {
|
|
3800
|
+
};
|
|
3801
|
+
|
|
3802
|
+
// src/features/analysis/index.ts
|
|
3803
|
+
import chalk4 from "chalk";
|
|
3804
|
+
import Configstore from "configstore";
|
|
3805
|
+
import Debug12 from "debug";
|
|
3806
|
+
import extract from "extract-zip";
|
|
3807
|
+
import fetch4 from "node-fetch";
|
|
3808
|
+
import open2 from "open";
|
|
3809
|
+
import semver from "semver";
|
|
3810
|
+
import tmp2 from "tmp";
|
|
3811
|
+
import { z as z13 } from "zod";
|
|
3812
|
+
|
|
3813
|
+
// src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
|
|
3814
|
+
import Debug4 from "debug";
|
|
3727
3815
|
|
|
3728
3816
|
// src/features/analysis/add_fix_comments_for_pr/utils.ts
|
|
3729
3817
|
import Debug3 from "debug";
|
|
3730
3818
|
import parseDiff2 from "parse-diff";
|
|
3731
|
-
import { z as
|
|
3819
|
+
import { z as z11 } from "zod";
|
|
3732
3820
|
|
|
3733
3821
|
// src/features/analysis/utils/by_key.ts
|
|
3734
3822
|
function keyBy(array, keyBy2) {
|
|
@@ -3960,7 +4048,7 @@ async function getRelevantVulenrabilitiesFromDiff(params) {
|
|
|
3960
4048
|
});
|
|
3961
4049
|
const lineAddedRanges = calculateRanges(fileNumbers);
|
|
3962
4050
|
const fileFilter = {
|
|
3963
|
-
path:
|
|
4051
|
+
path: z11.string().parse(file.to),
|
|
3964
4052
|
ranges: lineAddedRanges.map(([startLine, endLine]) => ({
|
|
3965
4053
|
endLine,
|
|
3966
4054
|
startLine
|
|
@@ -4267,30 +4355,30 @@ function subscribe(query, variables, callback, wsClientOptions) {
|
|
|
4267
4355
|
}
|
|
4268
4356
|
|
|
4269
4357
|
// src/features/analysis/graphql/types.ts
|
|
4270
|
-
import { z as
|
|
4271
|
-
var VulnerabilityReportIssueCodeNodeZ =
|
|
4272
|
-
vulnerabilityReportIssueId:
|
|
4273
|
-
path:
|
|
4274
|
-
startLine:
|
|
4275
|
-
vulnerabilityReportIssue:
|
|
4276
|
-
fixId:
|
|
4358
|
+
import { z as z12 } from "zod";
|
|
4359
|
+
var VulnerabilityReportIssueCodeNodeZ = z12.object({
|
|
4360
|
+
vulnerabilityReportIssueId: z12.string(),
|
|
4361
|
+
path: z12.string(),
|
|
4362
|
+
startLine: z12.number(),
|
|
4363
|
+
vulnerabilityReportIssue: z12.object({
|
|
4364
|
+
fixId: z12.string()
|
|
4277
4365
|
})
|
|
4278
4366
|
});
|
|
4279
|
-
var GetVulByNodesMetadataZ =
|
|
4280
|
-
vulnerabilityReportIssueCodeNodes:
|
|
4281
|
-
nonFixablePrVuls:
|
|
4282
|
-
aggregate:
|
|
4283
|
-
count:
|
|
4367
|
+
var GetVulByNodesMetadataZ = z12.object({
|
|
4368
|
+
vulnerabilityReportIssueCodeNodes: z12.array(VulnerabilityReportIssueCodeNodeZ),
|
|
4369
|
+
nonFixablePrVuls: z12.object({
|
|
4370
|
+
aggregate: z12.object({
|
|
4371
|
+
count: z12.number()
|
|
4284
4372
|
})
|
|
4285
4373
|
}),
|
|
4286
|
-
fixablePrVuls:
|
|
4287
|
-
aggregate:
|
|
4288
|
-
count:
|
|
4374
|
+
fixablePrVuls: z12.object({
|
|
4375
|
+
aggregate: z12.object({
|
|
4376
|
+
count: z12.number()
|
|
4289
4377
|
})
|
|
4290
4378
|
}),
|
|
4291
|
-
totalScanVulnerabilities:
|
|
4292
|
-
aggregate:
|
|
4293
|
-
count:
|
|
4379
|
+
totalScanVulnerabilities: z12.object({
|
|
4380
|
+
aggregate: z12.object({
|
|
4381
|
+
count: z12.number()
|
|
4294
4382
|
})
|
|
4295
4383
|
})
|
|
4296
4384
|
});
|
|
@@ -4563,6 +4651,12 @@ var GQLClient = class {
|
|
|
4563
4651
|
});
|
|
4564
4652
|
return res;
|
|
4565
4653
|
}
|
|
4654
|
+
async validateRepoUrl(args) {
|
|
4655
|
+
return this._clientSdk.validateRepoUrl(args);
|
|
4656
|
+
}
|
|
4657
|
+
async getReferenceData(args) {
|
|
4658
|
+
return this._clientSdk.gitReference(args);
|
|
4659
|
+
}
|
|
4566
4660
|
};
|
|
4567
4661
|
|
|
4568
4662
|
// src/features/analysis/pack.ts
|
|
@@ -5063,6 +5157,70 @@ function _getUrlForScmType({
|
|
|
5063
5157
|
};
|
|
5064
5158
|
}
|
|
5065
5159
|
}
|
|
5160
|
+
async function getScmTokenInfo(params) {
|
|
5161
|
+
const { gqlClient, repo } = params;
|
|
5162
|
+
const userInfo = await gqlClient.getUserInfo();
|
|
5163
|
+
if (!userInfo) {
|
|
5164
|
+
throw new Error("userInfo is null");
|
|
5165
|
+
}
|
|
5166
|
+
const scmConfigs = getFromArraySafe(userInfo.scmConfigs);
|
|
5167
|
+
return getScmConfig({
|
|
5168
|
+
url: repo,
|
|
5169
|
+
scmConfigs,
|
|
5170
|
+
includeOrgTokens: false
|
|
5171
|
+
});
|
|
5172
|
+
}
|
|
5173
|
+
async function getReport(params, { skipPrompts }) {
|
|
5174
|
+
const {
|
|
5175
|
+
scanner,
|
|
5176
|
+
repoUrl,
|
|
5177
|
+
gqlClient,
|
|
5178
|
+
sha,
|
|
5179
|
+
dirname,
|
|
5180
|
+
reference,
|
|
5181
|
+
cxProjectName,
|
|
5182
|
+
ci
|
|
5183
|
+
} = params;
|
|
5184
|
+
const tokenInfo = await getScmTokenInfo({ gqlClient, repo: repoUrl });
|
|
5185
|
+
const scm = await SCMLib.init(
|
|
5186
|
+
{
|
|
5187
|
+
url: repoUrl,
|
|
5188
|
+
accessToken: tokenInfo.accessToken,
|
|
5189
|
+
scmOrg: tokenInfo.scmOrg,
|
|
5190
|
+
scmType: tokenInfo.scmLibType
|
|
5191
|
+
},
|
|
5192
|
+
{ propagateExceptions: true }
|
|
5193
|
+
);
|
|
5194
|
+
const downloadUrl = await scm.getDownloadUrl(sha);
|
|
5195
|
+
const repositoryRoot = await downloadRepo({
|
|
5196
|
+
repoUrl,
|
|
5197
|
+
dirname,
|
|
5198
|
+
ci,
|
|
5199
|
+
authHeaders: scm.getAuthHeaders(),
|
|
5200
|
+
downloadUrl
|
|
5201
|
+
});
|
|
5202
|
+
const reportPath = path6.join(dirname, "report.json");
|
|
5203
|
+
switch (scanner) {
|
|
5204
|
+
case "snyk":
|
|
5205
|
+
await getSnykReport(reportPath, repositoryRoot, { skipPrompts });
|
|
5206
|
+
break;
|
|
5207
|
+
case "checkmarx":
|
|
5208
|
+
if (!cxProjectName) {
|
|
5209
|
+
throw new Error("cxProjectName is required for checkmarx scanner");
|
|
5210
|
+
}
|
|
5211
|
+
await getCheckmarxReport(
|
|
5212
|
+
{
|
|
5213
|
+
reportPath,
|
|
5214
|
+
repositoryRoot,
|
|
5215
|
+
branch: reference,
|
|
5216
|
+
projectName: cxProjectName
|
|
5217
|
+
},
|
|
5218
|
+
{ skipPrompts }
|
|
5219
|
+
);
|
|
5220
|
+
break;
|
|
5221
|
+
}
|
|
5222
|
+
return reportPath;
|
|
5223
|
+
}
|
|
5066
5224
|
async function _scan(params, { skipPrompts = false } = {}) {
|
|
5067
5225
|
const {
|
|
5068
5226
|
dirname,
|
|
@@ -5106,68 +5264,64 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
5106
5264
|
if (!repo) {
|
|
5107
5265
|
throw new Error("repo is required in case srcPath is not provided");
|
|
5108
5266
|
}
|
|
5109
|
-
const
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
}
|
|
5113
|
-
const scmConfigs = getFromArraySafe(userInfo.scmConfigs);
|
|
5114
|
-
const tokenInfo = getScmConfig({
|
|
5115
|
-
url: repo,
|
|
5116
|
-
scmConfigs,
|
|
5117
|
-
includeOrgTokens: false
|
|
5118
|
-
});
|
|
5119
|
-
const isRepoAvailable = await scmCanReachRepo({
|
|
5120
|
-
repoUrl: repo,
|
|
5121
|
-
accessToken: tokenInfo.accessToken,
|
|
5122
|
-
scmOrg: tokenInfo.scmOrg,
|
|
5123
|
-
scmType: getScmTypeFromScmLibType(tokenInfo.scmLibType)
|
|
5124
|
-
});
|
|
5267
|
+
const tokenInfo = await getScmTokenInfo({ gqlClient, repo });
|
|
5268
|
+
const validateRes = await gqlClient.validateRepoUrl({ repoUrl: repo });
|
|
5269
|
+
const isRepoAvailable = validateRes.validateRepoUrl?.__typename === "RepoValidationSuccess";
|
|
5125
5270
|
const cloudScmLibType = getCloudScmLibTypeFromUrl(repo);
|
|
5126
5271
|
const { authUrl: scmAuthUrl } = _getUrlForScmType({
|
|
5127
5272
|
scmLibType: cloudScmLibType
|
|
5128
5273
|
});
|
|
5129
|
-
let myToken = tokenInfo.accessToken;
|
|
5130
5274
|
if (!isRepoAvailable) {
|
|
5131
5275
|
if (ci || !cloudScmLibType || !scmAuthUrl) {
|
|
5132
5276
|
const errorMessage = scmAuthUrl ? `Cannot access repo ${repo}` : `Cannot access repo ${repo} with the provided token, please visit ${scmAuthUrl} to refresh your source control management system token`;
|
|
5133
5277
|
throw new Error(errorMessage);
|
|
5134
5278
|
}
|
|
5135
5279
|
if (cloudScmLibType && scmAuthUrl) {
|
|
5136
|
-
|
|
5137
|
-
const
|
|
5138
|
-
repoUrl: repo
|
|
5139
|
-
accessToken: myToken,
|
|
5140
|
-
scmOrg: tokenInfo.scmOrg,
|
|
5141
|
-
scmType: getScmTypeFromScmLibType(tokenInfo.scmLibType)
|
|
5280
|
+
await handleScmIntegration(tokenInfo.accessToken, scmAuthUrl, repo);
|
|
5281
|
+
const repoValidationResponse = await gqlClient.validateRepoUrl({
|
|
5282
|
+
repoUrl: repo
|
|
5142
5283
|
});
|
|
5284
|
+
const isRepoAvailable2 = repoValidationResponse.validateRepoUrl?.__typename === "RepoValidationSuccess";
|
|
5143
5285
|
if (!isRepoAvailable2) {
|
|
5144
5286
|
throw new Error(
|
|
5145
|
-
`Cannot access repo ${repo} with the provided credentials`
|
|
5287
|
+
`Cannot access repo ${repo} with the provided credentials: ${repoValidationResponse.validateRepoUrl?.__typename}`
|
|
5146
5288
|
);
|
|
5147
5289
|
}
|
|
5148
5290
|
}
|
|
5149
5291
|
}
|
|
5150
|
-
const
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5292
|
+
const revalidateRes = await gqlClient.validateRepoUrl({ repoUrl: repo });
|
|
5293
|
+
if (revalidateRes.validateRepoUrl?.__typename !== "RepoValidationSuccess") {
|
|
5294
|
+
throw new Error(
|
|
5295
|
+
`could not reach repo ${repo}: ${revalidateRes.validateRepoUrl?.__typename}`
|
|
5296
|
+
);
|
|
5297
|
+
}
|
|
5298
|
+
const reference = ref ?? revalidateRes.validateRepoUrl.defaultBranch;
|
|
5299
|
+
const getReferenceDataRes = await gqlClient.getReferenceData({
|
|
5300
|
+
reference,
|
|
5301
|
+
repoUrl: repo
|
|
5155
5302
|
});
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5303
|
+
if (getReferenceDataRes.gitReference?.__typename !== "GitReferenceData") {
|
|
5304
|
+
throw new Error(
|
|
5305
|
+
`Could not get reference data for ${reference}: ${getReferenceDataRes.gitReference?.__typename}`
|
|
5306
|
+
);
|
|
5307
|
+
}
|
|
5308
|
+
const { sha } = getReferenceDataRes.gitReference;
|
|
5160
5309
|
debug11("project id %s", projectId);
|
|
5161
5310
|
debug11("default branch %s", reference);
|
|
5162
|
-
const repositoryRoot = await downloadRepo({
|
|
5163
|
-
repoUrl: repo,
|
|
5164
|
-
dirname,
|
|
5165
|
-
ci,
|
|
5166
|
-
authHeaders: scm.getAuthHeaders(),
|
|
5167
|
-
downloadUrl
|
|
5168
|
-
});
|
|
5169
5311
|
if (command === "scan") {
|
|
5170
|
-
reportPath = await getReport(
|
|
5312
|
+
reportPath = await getReport(
|
|
5313
|
+
{
|
|
5314
|
+
scanner: SupportedScannersZ.parse(scanner),
|
|
5315
|
+
repoUrl: repo,
|
|
5316
|
+
sha,
|
|
5317
|
+
gqlClient,
|
|
5318
|
+
cxProjectName,
|
|
5319
|
+
dirname,
|
|
5320
|
+
reference,
|
|
5321
|
+
ci
|
|
5322
|
+
},
|
|
5323
|
+
{ skipPrompts }
|
|
5324
|
+
);
|
|
5171
5325
|
}
|
|
5172
5326
|
if (!reportPath) {
|
|
5173
5327
|
throw new Error("reportPath is null");
|
|
@@ -5191,7 +5345,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
5191
5345
|
spinner: mobbSpinner,
|
|
5192
5346
|
submitVulnerabilityReportVariables: {
|
|
5193
5347
|
fixReportId: reportUploadInfo.fixReportId,
|
|
5194
|
-
repoUrl:
|
|
5348
|
+
repoUrl: z13.string().parse(repo),
|
|
5195
5349
|
reference,
|
|
5196
5350
|
projectId,
|
|
5197
5351
|
vulnerabilityReportFileName: "report.json",
|
|
@@ -5210,29 +5364,6 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
5210
5364
|
});
|
|
5211
5365
|
await askToOpenAnalysis();
|
|
5212
5366
|
return reportUploadInfo.fixReportId;
|
|
5213
|
-
async function getReport(scanner2) {
|
|
5214
|
-
const reportPath2 = path6.join(dirname, "report.json");
|
|
5215
|
-
switch (scanner2) {
|
|
5216
|
-
case "snyk":
|
|
5217
|
-
await getSnykReport(reportPath2, repositoryRoot, { skipPrompts });
|
|
5218
|
-
break;
|
|
5219
|
-
case "checkmarx":
|
|
5220
|
-
if (!cxProjectName) {
|
|
5221
|
-
throw new Error("cxProjectName is required for checkmarx scanner");
|
|
5222
|
-
}
|
|
5223
|
-
await getCheckmarxReport(
|
|
5224
|
-
{
|
|
5225
|
-
reportPath: reportPath2,
|
|
5226
|
-
repositoryRoot,
|
|
5227
|
-
branch: reference,
|
|
5228
|
-
projectName: cxProjectName
|
|
5229
|
-
},
|
|
5230
|
-
{ skipPrompts }
|
|
5231
|
-
);
|
|
5232
|
-
break;
|
|
5233
|
-
}
|
|
5234
|
-
return reportPath2;
|
|
5235
|
-
}
|
|
5236
5367
|
async function askToOpenAnalysis() {
|
|
5237
5368
|
if (!repoUploadInfo || !reportUploadInfo) {
|
|
5238
5369
|
throw new Error("uploadS3BucketInfo is null");
|
|
@@ -5329,14 +5460,14 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
5329
5460
|
);
|
|
5330
5461
|
await open2(scmAuthUrl2);
|
|
5331
5462
|
for (let i = 0; i < LOGIN_MAX_WAIT / LOGIN_CHECK_DELAY; i++) {
|
|
5332
|
-
const
|
|
5333
|
-
if (!
|
|
5463
|
+
const userInfo = await gqlClient.getUserInfo();
|
|
5464
|
+
if (!userInfo) {
|
|
5334
5465
|
throw new CliError2("User info not found");
|
|
5335
5466
|
}
|
|
5336
|
-
const
|
|
5467
|
+
const scmConfigs = getFromArraySafe(userInfo.scmConfigs);
|
|
5337
5468
|
const tokenInfo2 = getScmConfig({
|
|
5338
5469
|
url: repoUrl,
|
|
5339
|
-
scmConfigs
|
|
5470
|
+
scmConfigs,
|
|
5340
5471
|
includeOrgTokens: false
|
|
5341
5472
|
});
|
|
5342
5473
|
if (tokenInfo2.accessToken && tokenInfo2.accessToken !== oldToken) {
|
|
@@ -5443,16 +5574,21 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
5443
5574
|
}
|
|
5444
5575
|
});
|
|
5445
5576
|
if (command === "review") {
|
|
5446
|
-
const params2 =
|
|
5447
|
-
repo:
|
|
5448
|
-
githubActionToken:
|
|
5577
|
+
const params2 = z13.object({
|
|
5578
|
+
repo: z13.string().url(),
|
|
5579
|
+
githubActionToken: z13.string()
|
|
5449
5580
|
}).parse({ repo, githubActionToken });
|
|
5450
|
-
const
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5581
|
+
const scm = await SCMLib.init(
|
|
5582
|
+
{
|
|
5583
|
+
url: params2.repo,
|
|
5584
|
+
accessToken: params2.githubActionToken,
|
|
5585
|
+
scmOrg: "",
|
|
5586
|
+
scmType: "GITHUB" /* GITHUB */
|
|
5587
|
+
},
|
|
5588
|
+
{
|
|
5589
|
+
propagateExceptions: true
|
|
5590
|
+
}
|
|
5591
|
+
);
|
|
5456
5592
|
await gqlClient.subscribeToAnalysis({
|
|
5457
5593
|
subscribeToAnalysisParams: {
|
|
5458
5594
|
analysisId: reportUploadInfo.fixReportId
|
|
@@ -5461,8 +5597,8 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
5461
5597
|
return addFixCommentsForPr({
|
|
5462
5598
|
analysisId,
|
|
5463
5599
|
gqlClient,
|
|
5464
|
-
scm
|
|
5465
|
-
scanner:
|
|
5600
|
+
scm,
|
|
5601
|
+
scanner: z13.nativeEnum(SCANNERS).parse(scanner)
|
|
5466
5602
|
});
|
|
5467
5603
|
},
|
|
5468
5604
|
callbackStates: ["Finished" /* Finished */]
|
|
@@ -5648,12 +5784,12 @@ var commitHashOption = {
|
|
|
5648
5784
|
};
|
|
5649
5785
|
var scmTypeOption = {
|
|
5650
5786
|
demandOption: true,
|
|
5651
|
-
describe: chalk5.bold("SCM type
|
|
5652
|
-
|
|
5787
|
+
describe: chalk5.bold("SCM type"),
|
|
5788
|
+
choices: Object.values(ScmType)
|
|
5653
5789
|
};
|
|
5654
5790
|
var urlOption = {
|
|
5655
5791
|
describe: chalk5.bold(
|
|
5656
|
-
|
|
5792
|
+
`URL of the repository (used in ${Object.values(ScmType).join(", ")})`
|
|
5657
5793
|
),
|
|
5658
5794
|
type: "string",
|
|
5659
5795
|
demandOption: true
|
|
@@ -5675,7 +5811,7 @@ var scmTokenOption = {
|
|
|
5675
5811
|
// src/args/validation.ts
|
|
5676
5812
|
import chalk6 from "chalk";
|
|
5677
5813
|
import path8 from "path";
|
|
5678
|
-
import { z as
|
|
5814
|
+
import { z as z14 } from "zod";
|
|
5679
5815
|
function throwRepoUrlErrorMessage({
|
|
5680
5816
|
error,
|
|
5681
5817
|
repoUrl,
|
|
@@ -5692,13 +5828,13 @@ Example:
|
|
|
5692
5828
|
)}`;
|
|
5693
5829
|
throw new CliError(formattedErrorMessage);
|
|
5694
5830
|
}
|
|
5695
|
-
var UrlZ =
|
|
5696
|
-
invalid_type_error:
|
|
5831
|
+
var UrlZ = z14.string({
|
|
5832
|
+
invalid_type_error: `is not a valid ${Object.values(ScmType).join("/ ")} URL`
|
|
5697
5833
|
}).refine((data) => !!sanityRepoURL(data), {
|
|
5698
|
-
message:
|
|
5834
|
+
message: `is not a valid ${Object.values(ScmType).join(" / ")} URL`
|
|
5699
5835
|
});
|
|
5700
5836
|
function validateOrganizationId(organizationId) {
|
|
5701
|
-
const orgIdValidation =
|
|
5837
|
+
const orgIdValidation = z14.string().uuid().nullish().safeParse(organizationId);
|
|
5702
5838
|
if (!orgIdValidation.success) {
|
|
5703
5839
|
throw new CliError(`organizationId: ${organizationId} is not a valid UUID`);
|
|
5704
5840
|
}
|
|
@@ -5855,20 +5991,15 @@ async function scanHandler(args) {
|
|
|
5855
5991
|
}
|
|
5856
5992
|
|
|
5857
5993
|
// src/args/commands/token.ts
|
|
5858
|
-
import { z as z14 } from "zod";
|
|
5859
5994
|
function addScmTokenBuilder(args) {
|
|
5860
5995
|
return args.option("scm-type", scmTypeOption).option("url", urlOption).option("token", scmTokenOption).option("organization", scmOrgOption).option("refresh-token", scmRefreshTokenOption).option("api-key", apiKeyOption).example(
|
|
5861
5996
|
"$0 add-scm-token --scm-type Ado --url https://dev.azure.com/adoorg/test/_git/repo --token abcdef0123456 --organization myOrg",
|
|
5862
|
-
|
|
5997
|
+
`Add your SCM (${Object.values(scmFriendlyText).join(", ")}) token to Mobb to enable automated fixes.`
|
|
5863
5998
|
).help().demandOption(["url", "token"]);
|
|
5864
5999
|
}
|
|
5865
|
-
function validateAddScmTokenOptions(argv) {
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
"\nError: --scm-type must reference a valid SCM type (GitHub, GitLab, Ado, Bitbutcket)"
|
|
5869
|
-
);
|
|
5870
|
-
}
|
|
5871
|
-
Object.values(scmValidationMap).forEach((validate) => validate(argv));
|
|
6000
|
+
async function validateAddScmTokenOptions(argv) {
|
|
6001
|
+
const scmType = argv["scm-type"];
|
|
6002
|
+
scmValidationMap[scmType];
|
|
5872
6003
|
}
|
|
5873
6004
|
var scmValidationMap = {
|
|
5874
6005
|
["GitHub" /* GitHub */]: () => {
|
|
@@ -5883,15 +6014,14 @@ var scmValidationMap = {
|
|
|
5883
6014
|
}
|
|
5884
6015
|
};
|
|
5885
6016
|
function validateAdo(argv) {
|
|
5886
|
-
|
|
5887
|
-
if ((urlObj.hostname.toLowerCase() === scmCloudHostname.Ado || urlObj.hostname.toLowerCase().endsWith(".visualstudio.com")) && !argv.organization) {
|
|
6017
|
+
if (!argv.organization) {
|
|
5888
6018
|
throw new CliError(
|
|
5889
6019
|
"\nError: --organization flag is required for Azure DevOps"
|
|
5890
6020
|
);
|
|
5891
6021
|
}
|
|
5892
6022
|
}
|
|
5893
6023
|
async function addScmTokenHandler(args) {
|
|
5894
|
-
validateAddScmTokenOptions(args);
|
|
6024
|
+
await validateAddScmTokenOptions(args);
|
|
5895
6025
|
await addScmToken(args);
|
|
5896
6026
|
}
|
|
5897
6027
|
|