mobbdev 0.0.108 → 0.0.112

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +1673 -1156
  2. package/package.json +7 -6
package/dist/index.mjs CHANGED
@@ -360,9 +360,16 @@ var SubmitVulnerabilityReportDocument = `
360
360
  var CreateCommunityUserDocument = `
361
361
  mutation CreateCommunityUser {
362
362
  initOrganizationAndProject {
363
- userId
364
- projectId
365
- organizationId
363
+ __typename
364
+ ... on InitOrganizationAndProjectGoodResponse {
365
+ projectId
366
+ userId
367
+ organizationId
368
+ }
369
+ ... on UserAlreadyInProjectError {
370
+ error
371
+ status
372
+ }
366
373
  }
367
374
  }
368
375
  `;
@@ -517,7 +524,7 @@ import fetch3 from "node-fetch";
517
524
  import open2 from "open";
518
525
  import semver from "semver";
519
526
  import tmp2 from "tmp";
520
- import { z as z11 } from "zod";
527
+ import { z as z12 } from "zod";
521
528
 
522
529
  // src/features/analysis/git.ts
523
530
  import Debug2 from "debug";
@@ -945,35 +952,46 @@ var GQLClient = class {
945
952
  import { Octokit as Octokit3 } from "@octokit/core";
946
953
  import Debug5 from "debug";
947
954
  import parseDiff2 from "parse-diff";
948
- import { z as z10 } from "zod";
955
+ import { z as z11 } from "zod";
949
956
 
950
957
  // src/features/analysis/scm/ado.ts
951
- import querystring2 from "node:querystring";
958
+ import querystring from "node:querystring";
952
959
  import * as api from "azure-devops-node-api";
953
- import { z as z9 } from "zod";
954
-
955
- // src/features/analysis/scm/scm.ts
956
- import { Octokit as Octokit2 } from "@octokit/core";
957
- import { z as z8 } from "zod";
958
-
959
- // src/features/analysis/scm/github/encryptSecret.ts
960
- import sodium from "libsodium-wrappers";
961
- async function encryptSecret(secret, key) {
962
- await sodium.ready;
963
- const binkey = sodium.from_base64(key, sodium.base64_variants.ORIGINAL);
964
- const binsec = sodium.from_string(secret);
965
- const encBytes = sodium.crypto_box_seal(binsec, binkey);
966
- return sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL);
967
- }
968
-
969
- // src/features/analysis/scm/github/github.ts
970
- import { RequestError } from "@octokit/request-error";
971
- import { Octokit } from "octokit";
972
960
  import { z as z3 } from "zod";
973
961
 
962
+ // src/features/analysis/scm/types.ts
963
+ var ReferenceType = /* @__PURE__ */ ((ReferenceType2) => {
964
+ ReferenceType2["BRANCH"] = "BRANCH";
965
+ ReferenceType2["COMMIT"] = "COMMIT";
966
+ ReferenceType2["TAG"] = "TAG";
967
+ return ReferenceType2;
968
+ })(ReferenceType || {});
969
+ var ScmLibScmType = /* @__PURE__ */ ((ScmLibScmType2) => {
970
+ ScmLibScmType2["GITHUB"] = "GITHUB";
971
+ ScmLibScmType2["GITLAB"] = "GITLAB";
972
+ ScmLibScmType2["ADO"] = "ADO";
973
+ ScmLibScmType2["BITBUCKET"] = "BITBUCKET";
974
+ return ScmLibScmType2;
975
+ })(ScmLibScmType || {});
976
+ var scmCloudUrl = {
977
+ GitLab: "https://gitlab.com",
978
+ GitHub: "https://github.com",
979
+ Ado: "https://dev.azure.com",
980
+ Bitbucket: "https://bitbucket.org"
981
+ };
982
+ var ScmType = /* @__PURE__ */ ((ScmType2) => {
983
+ ScmType2["GitHub"] = "GitHub";
984
+ ScmType2["GitLab"] = "GitLab";
985
+ ScmType2["Ado"] = "Ado";
986
+ ScmType2["Bitbucket"] = "Bitbucket";
987
+ return ScmType2;
988
+ })(ScmType || {});
989
+
974
990
  // src/features/analysis/scm/urlParser.ts
975
- function getRepoInfo(pathname, hostname, scmType) {
991
+ function detectAdoUrl(args) {
992
+ const { pathname, hostname, scmType } = args;
976
993
  const hostnameParts = hostname.split(".");
994
+ const adoHostname = new URL(scmCloudUrl.Ado).hostname;
977
995
  if (hostnameParts.length === 3 && hostnameParts[1] === "visualstudio" && hostnameParts[2] === "com") {
978
996
  if (pathname.length === 2 && pathname[0] === "_git") {
979
997
  return {
@@ -990,7 +1008,7 @@ function getRepoInfo(pathname, hostname, scmType) {
990
1008
  };
991
1009
  }
992
1010
  }
993
- if (hostname === "dev.azure.com" || scmType === "Ado" /* Ado */) {
1011
+ if (hostname === adoHostname || scmType === "Ado" /* Ado */) {
994
1012
  if (pathname.length === 3 && pathname[1] === "_git") {
995
1013
  return {
996
1014
  organization: pathname[0],
@@ -1006,7 +1024,12 @@ function getRepoInfo(pathname, hostname, scmType) {
1006
1024
  };
1007
1025
  }
1008
1026
  }
1009
- if (hostname === "github.com" || scmType === "GitHub" /* GitHub */) {
1027
+ return null;
1028
+ }
1029
+ function detectGithubUrl(args) {
1030
+ const { pathname, hostname, scmType } = args;
1031
+ const githubHostname = new URL(scmCloudUrl.GitHub).hostname;
1032
+ if (hostname === githubHostname || scmType === "GitHub" /* GitHub */) {
1010
1033
  if (pathname.length === 2) {
1011
1034
  return {
1012
1035
  organization: pathname[0],
@@ -1015,7 +1038,12 @@ function getRepoInfo(pathname, hostname, scmType) {
1015
1038
  };
1016
1039
  }
1017
1040
  }
1018
- if (hostname === "gitlab.com" || scmType === "GitLab" /* GitLab */) {
1041
+ return null;
1042
+ }
1043
+ function detectGitlabUrl(args) {
1044
+ const { pathname, hostname, scmType } = args;
1045
+ const gitlabHostname = new URL(scmCloudUrl.GitLab).hostname;
1046
+ if (hostname === gitlabHostname || scmType === "GitLab" /* GitLab */) {
1019
1047
  if (pathname.length >= 2) {
1020
1048
  return {
1021
1049
  organization: pathname[0],
@@ -1026,13 +1054,46 @@ function getRepoInfo(pathname, hostname, scmType) {
1026
1054
  }
1027
1055
  return null;
1028
1056
  }
1057
+ function detectBitbucketUrl(args) {
1058
+ const { pathname, hostname, scmType } = args;
1059
+ const bitbucketHostname = new URL(scmCloudUrl.Bitbucket).hostname;
1060
+ if (hostname === bitbucketHostname || scmType === "Bitbucket" /* Bitbucket */) {
1061
+ if (pathname.length === 2) {
1062
+ return {
1063
+ organization: pathname[0],
1064
+ projectName: void 0,
1065
+ repoName: pathname[1]
1066
+ };
1067
+ }
1068
+ }
1069
+ return null;
1070
+ }
1071
+ var getRepoUrlFunctionMap = {
1072
+ ["GitLab" /* GitLab */]: detectGitlabUrl,
1073
+ ["GitHub" /* GitHub */]: detectGithubUrl,
1074
+ ["Ado" /* Ado */]: detectAdoUrl,
1075
+ ["Bitbucket" /* Bitbucket */]: detectBitbucketUrl
1076
+ };
1077
+ function getRepoInfo(args) {
1078
+ for (const detectUrl of Object.values(getRepoUrlFunctionMap)) {
1079
+ const detectUrlRes = detectUrl(args);
1080
+ if (detectUrlRes) {
1081
+ return detectUrlRes;
1082
+ }
1083
+ }
1084
+ return null;
1085
+ }
1029
1086
  var NAME_REGEX = /[a-z0-9\-_.+]+/i;
1030
1087
  var parseScmURL = (scmURL, scmType) => {
1031
1088
  try {
1032
1089
  const url = new URL(scmURL);
1033
1090
  const hostname = url.hostname.toLowerCase();
1034
1091
  const projectPath = url.pathname.substring(1).replace(/.git$/i, "");
1035
- const repo = getRepoInfo(projectPath.split("/"), hostname, scmType);
1092
+ const repo = getRepoInfo({
1093
+ pathname: projectPath.split("/"),
1094
+ hostname,
1095
+ scmType
1096
+ });
1036
1097
  if (!repo)
1037
1098
  return null;
1038
1099
  const { organization, repoName, projectName } = repo;
@@ -1069,247 +1130,886 @@ var sanityRepoURL = (scmURL) => {
1069
1130
  }
1070
1131
  };
1071
1132
 
1072
- // src/features/analysis/scm/github/github.ts
1133
+ // src/features/analysis/scm/ado.ts
1073
1134
  function removeTrailingSlash(str) {
1074
1135
  return str.trim().replace(/\/+$/, "");
1075
1136
  }
1076
- var EnvVariablesZod = z3.object({
1077
- GITHUB_API_TOKEN: z3.string().optional()
1078
- });
1079
- var { GITHUB_API_TOKEN } = EnvVariablesZod.parse(process.env);
1080
- var GetBlameDocument = `
1081
- query GetBlame(
1082
- $owner: String!
1083
- $repo: String!
1084
- $ref: String!
1085
- $path: String!
1086
- ) {
1087
- repository(name: $repo, owner: $owner) {
1088
- # branch name
1089
- object(expression: $ref) {
1090
- # cast Target to a Commit
1091
- ... on Commit {
1092
- # full repo-relative path to blame file
1093
- blame(path: $path) {
1094
- ranges {
1095
- commit {
1096
- author {
1097
- user {
1098
- name
1099
- login
1100
- }
1101
- }
1102
- authoredDate
1103
- }
1104
- startingLine
1105
- endingLine
1106
- age
1107
- }
1108
- }
1109
- }
1110
-
1111
- }
1112
- }
1137
+ async function _getOrgsForOauthToken({ oauthToken }) {
1138
+ const profileZ = z3.object({
1139
+ displayName: z3.string(),
1140
+ publicAlias: z3.string().min(1),
1141
+ emailAddress: z3.string(),
1142
+ coreRevision: z3.number(),
1143
+ timeStamp: z3.string(),
1144
+ id: z3.string(),
1145
+ revision: z3.number()
1146
+ });
1147
+ const accountsZ = z3.object({
1148
+ count: z3.number(),
1149
+ value: z3.array(
1150
+ z3.object({
1151
+ accountId: z3.string(),
1152
+ accountUri: z3.string(),
1153
+ accountName: z3.string()
1154
+ })
1155
+ )
1156
+ });
1157
+ const profileRes = await fetch(
1158
+ "https://app.vssps.visualstudio.com/_apis/profile/profiles/me?api-version=6.0",
1159
+ {
1160
+ method: "GET",
1161
+ headers: {
1162
+ Authorization: `Bearer ${oauthToken}`
1113
1163
  }
1114
- `;
1115
- function getOktoKit(options) {
1116
- const token = options?.githubAuthToken ?? GITHUB_API_TOKEN ?? "";
1117
- return new Octokit({ auth: token });
1164
+ }
1165
+ );
1166
+ const profileJson = await profileRes.json();
1167
+ const profile = profileZ.parse(profileJson);
1168
+ const accountsRes = await fetch(
1169
+ `https://app.vssps.visualstudio.com/_apis/accounts?memberId=${profile.publicAlias}&api-version=6.0`,
1170
+ {
1171
+ method: "GET",
1172
+ headers: {
1173
+ Authorization: `Bearer ${oauthToken}`
1174
+ }
1175
+ }
1176
+ );
1177
+ const accountsJson = await accountsRes.json();
1178
+ const accounts = accountsZ.parse(accountsJson);
1179
+ const orgs = accounts.value.map((account) => account.accountName).filter((value, index, array) => array.indexOf(value) === index);
1180
+ return orgs;
1118
1181
  }
1119
- async function githubValidateParams(url, accessToken) {
1182
+ function _getPublicAdoClient({ orgName }) {
1183
+ const orgUrl = `https://dev.azure.com/${orgName}`;
1184
+ const authHandler = api.getPersonalAccessTokenHandler("");
1185
+ authHandler.canHandleAuthentication = () => false;
1186
+ authHandler.prepareRequest = (_options) => {
1187
+ return;
1188
+ };
1189
+ const connection = new api.WebApi(orgUrl, authHandler);
1190
+ return connection;
1191
+ }
1192
+ function getAdoTokenType(token) {
1193
+ if (token.includes(".")) {
1194
+ return "OAUTH" /* OAUTH */;
1195
+ }
1196
+ return "PAT" /* PAT */;
1197
+ }
1198
+ async function getAdoApiClient({
1199
+ accessToken,
1200
+ tokenOrg,
1201
+ orgName
1202
+ }) {
1203
+ if (!accessToken || tokenOrg && tokenOrg !== orgName) {
1204
+ return _getPublicAdoClient({ orgName });
1205
+ }
1206
+ const orgUrl = `https://dev.azure.com/${orgName}`;
1207
+ if (getAdoTokenType(accessToken) === "OAUTH" /* OAUTH */) {
1208
+ const connection2 = new api.WebApi(orgUrl, api.getBearerHandler(accessToken));
1209
+ return connection2;
1210
+ }
1211
+ const authHandler = api.getPersonalAccessTokenHandler(accessToken);
1212
+ const connection = new api.WebApi(orgUrl, authHandler);
1213
+ return connection;
1214
+ }
1215
+ async function adoValidateParams({
1216
+ url,
1217
+ accessToken,
1218
+ tokenOrg
1219
+ }) {
1120
1220
  try {
1121
- const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1122
- if (accessToken) {
1123
- await oktoKit.rest.users.getAuthenticated();
1221
+ if (!url && accessToken && getAdoTokenType(accessToken) === "OAUTH" /* OAUTH */) {
1222
+ await _getOrgsForOauthToken({ oauthToken: accessToken });
1223
+ return;
1124
1224
  }
1225
+ let org = tokenOrg;
1125
1226
  if (url) {
1126
- const { owner, repo } = parseGithubOwnerAndRepo(url);
1127
- await oktoKit.rest.repos.get({ repo, owner });
1227
+ const { owner } = parseAdoOwnerAndRepo(url);
1228
+ org = owner;
1128
1229
  }
1230
+ if (!org) {
1231
+ throw new InvalidRepoUrlError(`invalid ADO ORG ${org}`);
1232
+ }
1233
+ const api2 = await getAdoApiClient({
1234
+ accessToken,
1235
+ tokenOrg,
1236
+ orgName: org
1237
+ });
1238
+ await api2.connect();
1129
1239
  } catch (e) {
1130
1240
  const error = e;
1131
- const code = error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
1132
- if (code === 401 || code === 403) {
1133
- throw new InvalidAccessTokenError(`invalid github access token`);
1241
+ const code = error.code || error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
1242
+ const description = error.description || `${e}`;
1243
+ if (code === 401 || code === 403 || description.includes("401") || description.includes("403")) {
1244
+ throw new InvalidAccessTokenError(`invalid ADO access token`);
1134
1245
  }
1135
- if (code === 404) {
1136
- throw new InvalidRepoUrlError(`invalid github repo Url ${url}`);
1246
+ if (code === 404 || description.includes("404") || description.includes("Not Found")) {
1247
+ throw new InvalidRepoUrlError(`invalid ADO repo URL ${url}`);
1137
1248
  }
1138
1249
  throw e;
1139
1250
  }
1140
1251
  }
1141
- async function getGithubUsername(accessToken) {
1142
- const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1143
- const res = await oktoKit.rest.users.getAuthenticated();
1144
- return res.data.login;
1145
- }
1146
- async function getGithubIsUserCollaborator(username, accessToken, repoUrl) {
1252
+ async function getAdoIsUserCollaborator({
1253
+ accessToken,
1254
+ tokenOrg,
1255
+ repoUrl
1256
+ }) {
1147
1257
  try {
1148
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
1149
- const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1150
- const res = await oktoKit.rest.repos.checkCollaborator({
1151
- owner,
1152
- repo,
1153
- username
1258
+ const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
1259
+ const api2 = await getAdoApiClient({
1260
+ accessToken,
1261
+ tokenOrg,
1262
+ orgName: owner
1154
1263
  });
1155
- if (res.status === 204) {
1156
- return true;
1264
+ const git = await api2.getGitApi();
1265
+ const branches = await git.getBranches(repo, projectName);
1266
+ if (!branches || branches.length === 0) {
1267
+ throw new InvalidRepoUrlError("no branches");
1157
1268
  }
1269
+ return true;
1158
1270
  } catch (e) {
1159
1271
  return false;
1160
1272
  }
1161
- return false;
1162
1273
  }
1163
- async function getGithubPullRequestStatus(accessToken, repoUrl, prNumber) {
1164
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
1165
- const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1166
- const res = await oktoKit.rest.pulls.get({
1167
- owner,
1168
- repo,
1169
- pull_number: prNumber
1274
+ var adoStatusNumberToEnumMap = {
1275
+ 1: "active" /* active */,
1276
+ 2: "abandoned" /* abandoned */,
1277
+ 3: "completed" /* completed */,
1278
+ 4: "all" /* all */
1279
+ };
1280
+ async function getAdoPullRequestStatus({
1281
+ accessToken,
1282
+ tokenOrg,
1283
+ repoUrl,
1284
+ prNumber
1285
+ }) {
1286
+ const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
1287
+ const api2 = await getAdoApiClient({
1288
+ accessToken,
1289
+ tokenOrg,
1290
+ orgName: owner
1170
1291
  });
1171
- if (res.data.merged) {
1172
- return "merged";
1292
+ const git = await api2.getGitApi();
1293
+ const res = await git.getPullRequest(repo, prNumber, projectName);
1294
+ if (!res.status || res.status < 1 || res.status > 3) {
1295
+ throw new Error("bad pr status for ADO");
1173
1296
  }
1174
- if (res.data.draft) {
1175
- return "draft";
1176
- }
1177
- return res.data.state;
1297
+ return adoStatusNumberToEnumMap[res.status];
1178
1298
  }
1179
- async function getGithubIsRemoteBranch(accessToken, repoUrl, branch) {
1180
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
1181
- const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1299
+ async function getAdoIsRemoteBranch({
1300
+ accessToken,
1301
+ tokenOrg,
1302
+ repoUrl,
1303
+ branch
1304
+ }) {
1305
+ const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
1306
+ const api2 = await getAdoApiClient({
1307
+ accessToken,
1308
+ tokenOrg,
1309
+ orgName: owner
1310
+ });
1311
+ const git = await api2.getGitApi();
1182
1312
  try {
1183
- const res = await oktoKit.rest.repos.getBranch({
1184
- owner,
1185
- repo,
1186
- branch
1187
- });
1188
- return branch === res.data.name;
1313
+ const branchStatus = await git.getBranch(repo, branch, projectName);
1314
+ if (!branchStatus || !branchStatus.commit) {
1315
+ throw new InvalidRepoUrlError("no branch status");
1316
+ }
1317
+ return branchStatus.name === branch;
1189
1318
  } catch (e) {
1190
1319
  return false;
1191
1320
  }
1192
1321
  }
1193
- async function getGithubRepoList(accessToken) {
1194
- const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1195
- try {
1196
- const githubRepos = await getRepos(oktoKit);
1197
- return githubRepos.map(
1198
- (repo) => {
1199
- const repoLanguages = [];
1200
- if (repo.language) {
1201
- repoLanguages.push(repo.language);
1322
+ async function getAdoRepoList({
1323
+ orgName,
1324
+ tokenOrg,
1325
+ accessToken
1326
+ }) {
1327
+ let orgs = [];
1328
+ if (getAdoTokenType(accessToken) === "OAUTH" /* OAUTH */) {
1329
+ orgs = await _getOrgsForOauthToken({ oauthToken: accessToken });
1330
+ }
1331
+ if (orgs.length === 0 && !orgName) {
1332
+ throw new Error(`no orgs for ADO`);
1333
+ } else if (orgs.length === 0 && orgName) {
1334
+ orgs = [orgName];
1335
+ }
1336
+ const repos = (await Promise.allSettled(
1337
+ orgs.map(async (org) => {
1338
+ const orgApi = await getAdoApiClient({
1339
+ accessToken,
1340
+ tokenOrg,
1341
+ orgName: org
1342
+ });
1343
+ const gitOrg = await orgApi.getGitApi();
1344
+ const orgRepos = await gitOrg.getRepositories();
1345
+ const repoInfoList = (await Promise.allSettled(
1346
+ orgRepos.map(async (repo) => {
1347
+ if (!repo.name || !repo.remoteUrl || !repo.defaultBranch) {
1348
+ throw new InvalidRepoUrlError("bad repo");
1349
+ }
1350
+ const branch = await gitOrg.getBranch(
1351
+ repo.name,
1352
+ repo.defaultBranch.replace(/^refs\/heads\//, ""),
1353
+ repo.project?.name
1354
+ );
1355
+ return {
1356
+ repoName: repo.name,
1357
+ repoUrl: repo.remoteUrl.replace(
1358
+ /^[hH][tT][tT][pP][sS]:\/\/[^/]+@/,
1359
+ "https://"
1360
+ ),
1361
+ repoOwner: org,
1362
+ repoIsPublic: repo.project?.visibility === 2,
1363
+ //2 is public in the ADO API
1364
+ repoLanguages: [],
1365
+ repoUpdatedAt: branch.commit?.committer?.date?.toDateString() || repo.project?.lastUpdateTime?.toDateString() || (/* @__PURE__ */ new Date()).toDateString()
1366
+ };
1367
+ })
1368
+ )).reduce((acc, res) => {
1369
+ if (res.status === "fulfilled") {
1370
+ acc.push(res.value);
1202
1371
  }
1203
- return {
1204
- repoName: repo.name,
1205
- repoUrl: repo.html_url,
1206
- repoOwner: repo.owner.login,
1207
- repoLanguages,
1208
- repoIsPublic: !repo.private,
1209
- repoUpdatedAt: repo.updated_at
1210
- };
1211
- }
1212
- );
1213
- } catch (e) {
1214
- if (e instanceof RequestError && e.status === 401) {
1215
- return [];
1216
- }
1217
- if (e instanceof RequestError && e.status === 404) {
1218
- return [];
1372
+ return acc;
1373
+ }, []);
1374
+ return repoInfoList;
1375
+ })
1376
+ )).reduce((acc, res) => {
1377
+ if (res.status === "fulfilled") {
1378
+ return acc.concat(res.value);
1219
1379
  }
1220
- throw e;
1221
- }
1222
- }
1223
- async function getGithubBranchList(accessToken, repoUrl) {
1224
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
1225
- const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1226
- const res = await oktoKit.rest.repos.listBranches({
1227
- owner,
1228
- repo,
1229
- per_page: 1e3,
1230
- page: 1
1231
- });
1232
- return res.data.map((branch) => branch.name);
1380
+ return acc;
1381
+ }, []);
1382
+ return repos;
1233
1383
  }
1234
- async function createPullRequest(options) {
1235
- const { owner, repo } = parseGithubOwnerAndRepo(options.repoUrl);
1236
- const oktoKit = getOktoKit({ githubAuthToken: options.accessToken });
1237
- const res = await oktoKit.rest.pulls.create({
1238
- owner,
1239
- repo,
1240
- title: options.title,
1241
- body: options.body,
1242
- head: options.sourceBranchName,
1243
- base: options.targetBranchName,
1244
- draft: false,
1245
- maintainer_can_modify: true
1246
- });
1247
- return res.data.number;
1384
+ function getAdoPrUrl({
1385
+ url,
1386
+ prNumber
1387
+ }) {
1388
+ return `${url}/pullrequest/${prNumber}`;
1248
1389
  }
1249
- async function forkRepo(options) {
1250
- const { owner, repo } = parseGithubOwnerAndRepo(options.repoUrl);
1251
- const oktoKit = getOktoKit({ githubAuthToken: options.accessToken });
1252
- const res = await oktoKit.rest.repos.createFork({
1253
- owner,
1254
- repo,
1255
- default_branch_only: false
1256
- });
1257
- return { url: res.data.html_url ? String(res.data.html_url) : null };
1390
+ function getAdoDownloadUrl({
1391
+ repoUrl,
1392
+ branch
1393
+ }) {
1394
+ const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
1395
+ const url = new URL(repoUrl);
1396
+ const origin = url.origin.toLowerCase().endsWith(".visualstudio.com") ? "https://dev.azure.com" : url.origin.toLowerCase();
1397
+ return `${origin}/${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`;
1258
1398
  }
1259
- async function getRepos(oktoKit) {
1260
- const res = await oktoKit.request("GET /user/repos?sort=updated", {
1261
- headers: {
1262
- "X-GitHub-Api-Version": "2022-11-28",
1263
- per_page: 100
1264
- }
1399
+ async function getAdoBranchList({
1400
+ accessToken,
1401
+ tokenOrg,
1402
+ repoUrl
1403
+ }) {
1404
+ const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
1405
+ const api2 = await getAdoApiClient({
1406
+ accessToken,
1407
+ tokenOrg,
1408
+ orgName: owner
1265
1409
  });
1266
- return res.data;
1267
- }
1268
- async function getGithubRepoDefaultBranch(repoUrl, options) {
1269
- const oktoKit = getOktoKit(options);
1270
- const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
1271
- return (await oktoKit.rest.repos.get({ repo, owner })).data.default_branch;
1272
- }
1273
- async function getGithubReferenceData({ ref, gitHubUrl }, options) {
1274
- const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
1275
- let res;
1410
+ const git = await api2.getGitApi();
1276
1411
  try {
1277
- const oktoKit = getOktoKit(options);
1278
- res = await Promise.any([
1279
- getBranch({ owner, repo, branch: ref }, oktoKit).then((result) => ({
1280
- date: result.data.commit.commit.committer?.date ? new Date(result.data.commit.commit.committer?.date) : void 0,
1281
- type: "BRANCH" /* BRANCH */,
1282
- sha: result.data.commit.sha
1283
- })),
1284
- getCommit({ commitSha: ref, repo, owner }, oktoKit).then((commit) => ({
1285
- date: new Date(commit.data.committer.date),
1286
- type: "COMMIT" /* COMMIT */,
1287
- sha: commit.data.sha
1288
- })),
1289
- getTagDate({ owner, repo, tag: ref }, oktoKit).then((data) => ({
1290
- date: new Date(data.date),
1291
- type: "TAG" /* TAG */,
1292
- sha: data.sha
1293
- }))
1294
- ]);
1295
- return res;
1412
+ const res = await git.getBranches(repo, projectName);
1413
+ res.sort((a, b) => {
1414
+ if (!a.commit?.committer?.date || !b.commit?.committer?.date) {
1415
+ return 0;
1416
+ }
1417
+ return b.commit?.committer?.date.getTime() - a.commit?.committer?.date.getTime();
1418
+ });
1419
+ return res.reduce((acc, branch) => {
1420
+ if (!branch.name) {
1421
+ return acc;
1422
+ }
1423
+ acc.push(branch.name);
1424
+ return acc;
1425
+ }, []);
1296
1426
  } catch (e) {
1297
- if (e instanceof AggregateError) {
1298
- throw new RefNotFoundError(`ref: ${ref} does not exist`);
1299
- }
1300
- throw e;
1427
+ return [];
1301
1428
  }
1302
1429
  }
1303
- async function getBranch({ branch, owner, repo }, oktoKit) {
1304
- return oktoKit.rest.repos.getBranch({
1305
- branch,
1306
- owner,
1307
- repo
1430
+ async function createAdoPullRequest(options) {
1431
+ const { owner, repo, projectName } = parseAdoOwnerAndRepo(options.repoUrl);
1432
+ const api2 = await getAdoApiClient({
1433
+ accessToken: options.accessToken,
1434
+ tokenOrg: options.tokenOrg,
1435
+ orgName: owner
1308
1436
  });
1437
+ const git = await api2.getGitApi();
1438
+ const res = await git.createPullRequest(
1439
+ {
1440
+ sourceRefName: `refs/heads/${options.sourceBranchName}`,
1441
+ targetRefName: `refs/heads/${options.targetBranchName}`,
1442
+ title: options.title,
1443
+ description: options.body
1444
+ },
1445
+ repo,
1446
+ projectName
1447
+ );
1448
+ return res.pullRequestId;
1309
1449
  }
1310
- async function getTagDate({ tag, owner, repo }, oktoKit) {
1311
- const refResponse = await oktoKit.rest.git.getRef({
1312
- ref: `tags/${tag}`,
1450
+ async function getAdoRepoDefaultBranch({
1451
+ repoUrl,
1452
+ tokenOrg,
1453
+ accessToken
1454
+ }) {
1455
+ const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
1456
+ const api2 = await getAdoApiClient({
1457
+ accessToken,
1458
+ tokenOrg,
1459
+ orgName: owner
1460
+ });
1461
+ const git = await api2.getGitApi();
1462
+ const branches = await git.getBranches(repo, projectName);
1463
+ if (!branches || branches.length === 0) {
1464
+ throw new InvalidRepoUrlError("no branches");
1465
+ }
1466
+ const res = branches.find((branch) => branch.isBaseVersion);
1467
+ if (!res || !res.name) {
1468
+ throw new InvalidRepoUrlError("no default branch");
1469
+ }
1470
+ return res.name;
1471
+ }
1472
+ async function getAdoReferenceData({
1473
+ ref,
1474
+ repoUrl,
1475
+ accessToken,
1476
+ tokenOrg
1477
+ }) {
1478
+ const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
1479
+ const api2 = await getAdoApiClient({
1480
+ accessToken,
1481
+ tokenOrg,
1482
+ orgName: owner
1483
+ });
1484
+ if (!projectName) {
1485
+ throw new InvalidUrlPatternError("no project name");
1486
+ }
1487
+ const git = await api2.getGitApi();
1488
+ const results = await Promise.allSettled([
1489
+ (async () => {
1490
+ const res = await git.getBranch(repo, ref, projectName);
1491
+ if (!res.commit || !res.commit.commitId) {
1492
+ throw new InvalidRepoUrlError("no commit on branch");
1493
+ }
1494
+ return {
1495
+ sha: res.commit.commitId,
1496
+ type: "BRANCH" /* BRANCH */,
1497
+ date: res.commit.committer?.date || /* @__PURE__ */ new Date()
1498
+ };
1499
+ })(),
1500
+ (async () => {
1501
+ const res = await git.getCommits(
1502
+ repo,
1503
+ {
1504
+ fromCommitId: ref,
1505
+ toCommitId: ref,
1506
+ $top: 1
1507
+ },
1508
+ projectName
1509
+ );
1510
+ const commit = res[0];
1511
+ if (!commit || !commit.commitId) {
1512
+ throw new Error("no commit");
1513
+ }
1514
+ return {
1515
+ sha: commit.commitId,
1516
+ type: "COMMIT" /* COMMIT */,
1517
+ date: commit.committer?.date || /* @__PURE__ */ new Date()
1518
+ };
1519
+ })(),
1520
+ (async () => {
1521
+ const res = await git.getRefs(repo, projectName, `tags/${ref}`);
1522
+ if (!res[0] || !res[0].objectId) {
1523
+ throw new Error("no tag ref");
1524
+ }
1525
+ let objectId = res[0].objectId;
1526
+ try {
1527
+ const tag = await git.getAnnotatedTag(projectName, repo, objectId);
1528
+ if (tag.taggedObject?.objectId) {
1529
+ objectId = tag.taggedObject.objectId;
1530
+ }
1531
+ } catch (e) {
1532
+ }
1533
+ const commitRes2 = await git.getCommits(
1534
+ repo,
1535
+ {
1536
+ fromCommitId: objectId,
1537
+ toCommitId: objectId,
1538
+ $top: 1
1539
+ },
1540
+ projectName
1541
+ );
1542
+ const commit = commitRes2[0];
1543
+ if (!commit) {
1544
+ throw new Error("no commit");
1545
+ }
1546
+ return {
1547
+ sha: objectId,
1548
+ type: "TAG" /* TAG */,
1549
+ date: commit.committer?.date || /* @__PURE__ */ new Date()
1550
+ };
1551
+ })()
1552
+ ]);
1553
+ const [branchRes, commitRes, tagRes] = results;
1554
+ if (tagRes.status === "fulfilled") {
1555
+ return tagRes.value;
1556
+ }
1557
+ if (branchRes.status === "fulfilled") {
1558
+ return branchRes.value;
1559
+ }
1560
+ if (commitRes.status === "fulfilled") {
1561
+ return commitRes.value;
1562
+ }
1563
+ throw new RefNotFoundError(`ref: ${ref} does not exist`);
1564
+ }
1565
+ function parseAdoOwnerAndRepo(adoUrl) {
1566
+ adoUrl = removeTrailingSlash(adoUrl);
1567
+ const parsingResult = parseScmURL(adoUrl, "Ado" /* Ado */);
1568
+ if (!parsingResult || parsingResult.hostname !== "dev.azure.com" && !parsingResult.hostname.endsWith(".visualstudio.com")) {
1569
+ throw new InvalidUrlPatternError(`invalid ADO repo URL: ${adoUrl}`);
1570
+ }
1571
+ const { organization, repoName, projectName, projectPath, pathElements } = parsingResult;
1572
+ return {
1573
+ owner: organization,
1574
+ repo: repoName,
1575
+ projectName,
1576
+ projectPath,
1577
+ pathElements
1578
+ };
1579
+ }
1580
+ async function getAdoBlameRanges() {
1581
+ return [];
1582
+ }
1583
+ var ADO_ACCESS_TOKEN_URL = "https://app.vssps.visualstudio.com/oauth2/token";
1584
+ var AdoAuthResultZ = z3.object({
1585
+ access_token: z3.string().min(1),
1586
+ token_type: z3.string().min(1),
1587
+ refresh_token: z3.string().min(1)
1588
+ });
1589
+ async function getAdoToken({
1590
+ token,
1591
+ adoClientSecret,
1592
+ tokenType,
1593
+ redirectUri
1594
+ }) {
1595
+ const res = await fetch(ADO_ACCESS_TOKEN_URL, {
1596
+ method: "POST",
1597
+ headers: {
1598
+ Accept: "application/json",
1599
+ "Content-Type": "application/x-www-form-urlencoded"
1600
+ },
1601
+ body: querystring.stringify({
1602
+ client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
1603
+ client_assertion: adoClientSecret,
1604
+ redirect_uri: redirectUri,
1605
+ assertion: token,
1606
+ grant_type: tokenType === "code" /* CODE */ ? "urn:ietf:params:oauth:grant-type:jwt-bearer" : "refresh_token"
1607
+ })
1608
+ });
1609
+ const authResult = await res.json();
1610
+ return AdoAuthResultZ.parse(authResult);
1611
+ }
1612
+ var AdoSdk = {
1613
+ getAdoApiClient,
1614
+ adoValidateParams,
1615
+ getAdoIsUserCollaborator,
1616
+ getAdoPullRequestStatus,
1617
+ getAdoIsRemoteBranch,
1618
+ getAdoRepoList,
1619
+ getAdoDownloadUrl,
1620
+ getAdoBranchList,
1621
+ createAdoPullRequest,
1622
+ getAdoRepoDefaultBranch,
1623
+ getAdoReferenceData,
1624
+ parseAdoOwnerAndRepo,
1625
+ getAdoBlameRanges,
1626
+ getAdoToken,
1627
+ getAdoTokenType
1628
+ };
1629
+
1630
+ // src/features/analysis/scm/bitbucket/bitbucket.ts
1631
+ import querystring3 from "node:querystring";
1632
+ import * as bitbucketPkg from "bitbucket";
1633
+ import { z as z10 } from "zod";
1634
+
1635
+ // src/features/analysis/scm/scm.ts
1636
+ import { Octokit as Octokit2 } from "@octokit/core";
1637
+ import { z as z9 } from "zod";
1638
+
1639
+ // src/features/analysis/scm/github/encryptSecret.ts
1640
+ import sodium from "libsodium-wrappers";
1641
+ async function encryptSecret(secret, key) {
1642
+ await sodium.ready;
1643
+ const binkey = sodium.from_base64(key, sodium.base64_variants.ORIGINAL);
1644
+ const binsec = sodium.from_string(secret);
1645
+ const encBytes = sodium.crypto_box_seal(binsec, binkey);
1646
+ return sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL);
1647
+ }
1648
+
1649
+ // src/features/analysis/scm/github/github.ts
1650
+ import { RequestError } from "@octokit/request-error";
1651
+ import { Octokit } from "octokit";
1652
+ import { z as z4 } from "zod";
1653
+
1654
+ // src/features/analysis/scm/utils/get_issue_type.ts
1655
+ var getIssueType = (issueType) => {
1656
+ switch (issueType) {
1657
+ case "SQL_Injection" /* SqlInjection */:
1658
+ return "SQL Injection";
1659
+ case "CMDi_relative_path_command" /* CmDiRelativePathCommand */:
1660
+ return "Relative Path Command Injection";
1661
+ case "CMDi" /* CmDi */:
1662
+ return "Command Injection";
1663
+ case "XXE" /* Xxe */:
1664
+ return "XXE";
1665
+ case "XSS" /* Xss */:
1666
+ return "XSS";
1667
+ case "PT" /* Pt */:
1668
+ return "Path Traversal";
1669
+ case "ZIP_SLIP" /* ZipSlip */:
1670
+ return "Zip Slip";
1671
+ case "INSECURE_RANDOMNESS" /* InsecureRandomness */:
1672
+ return "Insecure Randomness";
1673
+ case "SSRF" /* Ssrf */:
1674
+ return "Server Side Request Forgery";
1675
+ case "TYPE_CONFUSION" /* TypeConfusion */:
1676
+ return "Type Confusion";
1677
+ case "REGEX_INJECTION" /* RegexInjection */:
1678
+ return "Regular Expression Injection";
1679
+ case "INCOMPLETE_URL_SANITIZATION" /* IncompleteUrlSanitization */:
1680
+ return "Incomplete URL Sanitization";
1681
+ case "LOG_FORGING" /* LogForging */:
1682
+ return "Log Forging";
1683
+ case "LOCALE_DEPENDENT_COMPARISON" /* LocaleDependentComparison */:
1684
+ return "Locale Dependent Comparison";
1685
+ case "MISSING_CHECK_AGAINST_NULL" /* MissingCheckAgainstNull */:
1686
+ return "Missing Check against Null";
1687
+ case "PASSWORD_IN_COMMENT" /* PasswordInComment */:
1688
+ return "Password in Comment";
1689
+ case "OVERLY_BROAD_CATCH" /* OverlyBroadCatch */:
1690
+ return "Poor Error Handling: Overly Broad Catch";
1691
+ case "USE_OF_SYSTEM_OUTPUT_STREAM" /* UseOfSystemOutputStream */:
1692
+ return "Use of System.out/System.err";
1693
+ case "DANGEROUS_FUNCTION_OVERFLOW" /* DangerousFunctionOverflow */:
1694
+ return "Use of dangerous function";
1695
+ case "DOS_STRING_BUILDER" /* DosStringBuilder */:
1696
+ return "Denial of Service: StringBuilder";
1697
+ case "OPEN_REDIRECT" /* OpenRedirect */:
1698
+ return "Open Redirect";
1699
+ case "WEAK_XML_SCHEMA_UNBOUNDED_OCCURRENCES" /* WeakXmlSchemaUnboundedOccurrences */:
1700
+ return "Weak XML Schema: Unbounded Occurrences";
1701
+ case "SYSTEM_INFORMATION_LEAK" /* SystemInformationLeak */:
1702
+ return "System Information Leak";
1703
+ case "HTTP_RESPONSE_SPLITTING" /* HttpResponseSplitting */:
1704
+ return "HTTP response splitting";
1705
+ case "HTTP_ONLY_COOKIE" /* HttpOnlyCookie */:
1706
+ return "Cookie is not HttpOnly";
1707
+ case "INSECURE_COOKIE" /* InsecureCookie */:
1708
+ return "Insecure Cookie";
1709
+ case "TRUST_BOUNDARY_VIOLATION" /* TrustBoundaryViolation */:
1710
+ return "Trust Boundary Violation";
1711
+ case "MISSING_EQUALS_OR_HASHCODE" /* MissingEqualsOrHashcode */:
1712
+ return "Missing equals or hashcode method";
1713
+ default: {
1714
+ return issueType ? issueType.replaceAll("_", " ") : "Other";
1715
+ }
1716
+ }
1717
+ };
1718
+
1719
+ // src/features/analysis/scm/utils/index.ts
1720
+ function getFixUrlWithRedirect(params) {
1721
+ const {
1722
+ fixId,
1723
+ projectId,
1724
+ organizationId,
1725
+ analysisId,
1726
+ redirectUrl,
1727
+ appBaseUrl,
1728
+ commentId
1729
+ } = params;
1730
+ const searchParams = new URLSearchParams();
1731
+ searchParams.append("commit_redirect_url", redirectUrl);
1732
+ searchParams.append("comment_id", commentId.toString());
1733
+ return `${getFixUrl({
1734
+ appBaseUrl,
1735
+ fixId,
1736
+ projectId,
1737
+ organizationId,
1738
+ analysisId
1739
+ })}?${searchParams.toString()}`;
1740
+ }
1741
+ function getFixUrl({
1742
+ appBaseUrl,
1743
+ fixId,
1744
+ projectId,
1745
+ organizationId,
1746
+ analysisId
1747
+ }) {
1748
+ return `${appBaseUrl}/organization/${organizationId}/project/${projectId}/report/${analysisId}/fix/${fixId}`;
1749
+ }
1750
+ function getCommitUrl(params) {
1751
+ const {
1752
+ fixId,
1753
+ projectId,
1754
+ organizationId,
1755
+ analysisId,
1756
+ redirectUrl,
1757
+ appBaseUrl,
1758
+ commentId
1759
+ } = params;
1760
+ const searchParams = new URLSearchParams();
1761
+ searchParams.append("redirect_url", redirectUrl);
1762
+ searchParams.append("comment_id", commentId.toString());
1763
+ return `${getFixUrl({
1764
+ appBaseUrl,
1765
+ fixId,
1766
+ projectId,
1767
+ organizationId,
1768
+ analysisId
1769
+ })}/commit?${searchParams.toString()}`;
1770
+ }
1771
+ function removeTrailingSlash2(str) {
1772
+ return str.trim().replace(/\/+$/, "");
1773
+ }
1774
+
1775
+ // src/features/analysis/scm/github/github.ts
1776
+ var EnvVariablesZod = z4.object({
1777
+ GITHUB_API_TOKEN: z4.string().optional()
1778
+ });
1779
+ var { GITHUB_API_TOKEN } = EnvVariablesZod.parse(process.env);
1780
+ var GetBlameDocument = `
1781
+ query GetBlame(
1782
+ $owner: String!
1783
+ $repo: String!
1784
+ $ref: String!
1785
+ $path: String!
1786
+ ) {
1787
+ repository(name: $repo, owner: $owner) {
1788
+ # branch name
1789
+ object(expression: $ref) {
1790
+ # cast Target to a Commit
1791
+ ... on Commit {
1792
+ # full repo-relative path to blame file
1793
+ blame(path: $path) {
1794
+ ranges {
1795
+ commit {
1796
+ author {
1797
+ user {
1798
+ name
1799
+ login
1800
+ }
1801
+ }
1802
+ authoredDate
1803
+ }
1804
+ startingLine
1805
+ endingLine
1806
+ age
1807
+ }
1808
+ }
1809
+ }
1810
+
1811
+ }
1812
+ }
1813
+ }
1814
+ `;
1815
+ function getOktoKit(options) {
1816
+ const token = options?.githubAuthToken ?? GITHUB_API_TOKEN ?? "";
1817
+ return new Octokit({ auth: token });
1818
+ }
1819
+ async function githubValidateParams(url, accessToken) {
1820
+ try {
1821
+ const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1822
+ if (accessToken) {
1823
+ await oktoKit.rest.users.getAuthenticated();
1824
+ }
1825
+ if (url) {
1826
+ const { owner, repo } = parseGithubOwnerAndRepo(url);
1827
+ await oktoKit.rest.repos.get({ repo, owner });
1828
+ }
1829
+ } catch (e) {
1830
+ const error = e;
1831
+ const code = error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
1832
+ if (code === 401 || code === 403) {
1833
+ throw new InvalidAccessTokenError(`invalid github access token`);
1834
+ }
1835
+ if (code === 404) {
1836
+ throw new InvalidRepoUrlError(`invalid github repo Url ${url}`);
1837
+ }
1838
+ throw e;
1839
+ }
1840
+ }
1841
+ async function getGithubUsername(accessToken) {
1842
+ const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1843
+ const res = await oktoKit.rest.users.getAuthenticated();
1844
+ return res.data.login;
1845
+ }
1846
+ async function getGithubIsUserCollaborator(username, accessToken, repoUrl) {
1847
+ try {
1848
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
1849
+ const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1850
+ const res = await oktoKit.rest.repos.checkCollaborator({
1851
+ owner,
1852
+ repo,
1853
+ username
1854
+ });
1855
+ if (res.status === 204) {
1856
+ return true;
1857
+ }
1858
+ } catch (e) {
1859
+ return false;
1860
+ }
1861
+ return false;
1862
+ }
1863
+ async function getGithubPullRequestStatus(accessToken, repoUrl, prNumber) {
1864
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
1865
+ const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1866
+ const res = await oktoKit.rest.pulls.get({
1867
+ owner,
1868
+ repo,
1869
+ pull_number: prNumber
1870
+ });
1871
+ if (res.data.merged) {
1872
+ return "merged";
1873
+ }
1874
+ if (res.data.draft) {
1875
+ return "draft";
1876
+ }
1877
+ return res.data.state;
1878
+ }
1879
+ async function getGithubIsRemoteBranch(accessToken, repoUrl, branch) {
1880
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
1881
+ const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1882
+ try {
1883
+ const res = await oktoKit.rest.repos.getBranch({
1884
+ owner,
1885
+ repo,
1886
+ branch
1887
+ });
1888
+ return branch === res.data.name;
1889
+ } catch (e) {
1890
+ return false;
1891
+ }
1892
+ }
1893
+ async function getGithubRepoList(accessToken) {
1894
+ const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1895
+ try {
1896
+ const githubRepos = await getRepos(oktoKit);
1897
+ return githubRepos.map(
1898
+ (repo) => {
1899
+ const repoLanguages = [];
1900
+ if (repo.language) {
1901
+ repoLanguages.push(repo.language);
1902
+ }
1903
+ return {
1904
+ repoName: repo.name,
1905
+ repoUrl: repo.html_url,
1906
+ repoOwner: repo.owner.login,
1907
+ repoLanguages,
1908
+ repoIsPublic: !repo.private,
1909
+ repoUpdatedAt: repo.updated_at
1910
+ };
1911
+ }
1912
+ );
1913
+ } catch (e) {
1914
+ if (e instanceof RequestError && e.status === 401) {
1915
+ return [];
1916
+ }
1917
+ if (e instanceof RequestError && e.status === 404) {
1918
+ return [];
1919
+ }
1920
+ throw e;
1921
+ }
1922
+ }
1923
+ async function getGithubBranchList(accessToken, repoUrl) {
1924
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
1925
+ const oktoKit = getOktoKit({ githubAuthToken: accessToken });
1926
+ const res = await oktoKit.rest.repos.listBranches({
1927
+ owner,
1928
+ repo,
1929
+ per_page: 1e3,
1930
+ page: 1
1931
+ });
1932
+ return res.data.map((branch) => branch.name);
1933
+ }
1934
+ async function createPullRequest(options) {
1935
+ const { owner, repo } = parseGithubOwnerAndRepo(options.repoUrl);
1936
+ const oktoKit = getOktoKit({ githubAuthToken: options.accessToken });
1937
+ const res = await oktoKit.rest.pulls.create({
1938
+ owner,
1939
+ repo,
1940
+ title: options.title,
1941
+ body: options.body,
1942
+ head: options.sourceBranchName,
1943
+ base: options.targetBranchName,
1944
+ draft: false,
1945
+ maintainer_can_modify: true
1946
+ });
1947
+ return res.data.number;
1948
+ }
1949
+ async function forkRepo(options) {
1950
+ const { owner, repo } = parseGithubOwnerAndRepo(options.repoUrl);
1951
+ const oktoKit = getOktoKit({ githubAuthToken: options.accessToken });
1952
+ const res = await oktoKit.rest.repos.createFork({
1953
+ owner,
1954
+ repo,
1955
+ default_branch_only: false
1956
+ });
1957
+ return { url: res.data.html_url ? String(res.data.html_url) : null };
1958
+ }
1959
+ async function getRepos(oktoKit) {
1960
+ const res = await oktoKit.request("GET /user/repos?sort=updated", {
1961
+ headers: {
1962
+ "X-GitHub-Api-Version": "2022-11-28",
1963
+ per_page: 100
1964
+ }
1965
+ });
1966
+ return res.data;
1967
+ }
1968
+ async function getGithubRepoDefaultBranch(repoUrl, options) {
1969
+ const oktoKit = getOktoKit(options);
1970
+ const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
1971
+ return (await oktoKit.rest.repos.get({ repo, owner })).data.default_branch;
1972
+ }
1973
+ async function getGithubReferenceData({ ref, gitHubUrl }, options) {
1974
+ const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
1975
+ let res;
1976
+ try {
1977
+ const oktoKit = getOktoKit(options);
1978
+ res = await Promise.any([
1979
+ getBranch({ owner, repo, branch: ref }, oktoKit).then((result) => ({
1980
+ date: result.data.commit.commit.committer?.date ? new Date(result.data.commit.commit.committer?.date) : void 0,
1981
+ type: "BRANCH" /* BRANCH */,
1982
+ sha: result.data.commit.sha
1983
+ })),
1984
+ getCommit({ commitSha: ref, repo, owner }, oktoKit).then((commit) => ({
1985
+ date: new Date(commit.data.committer.date),
1986
+ type: "COMMIT" /* COMMIT */,
1987
+ sha: commit.data.sha
1988
+ })),
1989
+ getTagDate({ owner, repo, tag: ref }, oktoKit).then((data) => ({
1990
+ date: new Date(data.date),
1991
+ type: "TAG" /* TAG */,
1992
+ sha: data.sha
1993
+ }))
1994
+ ]);
1995
+ return res;
1996
+ } catch (e) {
1997
+ if (e instanceof AggregateError) {
1998
+ throw new RefNotFoundError(`ref: ${ref} does not exist`);
1999
+ }
2000
+ throw e;
2001
+ }
2002
+ }
2003
+ async function getBranch({ branch, owner, repo }, oktoKit) {
2004
+ return oktoKit.rest.repos.getBranch({
2005
+ branch,
2006
+ owner,
2007
+ repo
2008
+ });
2009
+ }
2010
+ async function getTagDate({ tag, owner, repo }, oktoKit) {
2011
+ const refResponse = await oktoKit.rest.git.getRef({
2012
+ ref: `tags/${tag}`,
1313
2013
  owner,
1314
2014
  repo
1315
2015
  });
@@ -1347,7 +2047,7 @@ async function getCommit({
1347
2047
  });
1348
2048
  }
1349
2049
  function parseGithubOwnerAndRepo(gitHubUrl) {
1350
- gitHubUrl = removeTrailingSlash(gitHubUrl);
2050
+ gitHubUrl = removeTrailingSlash2(gitHubUrl);
1351
2051
  const parsingResult = parseScmURL(gitHubUrl, "GitHub" /* GitHub */);
1352
2052
  if (!parsingResult || parsingResult.hostname !== "github.com") {
1353
2053
  throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
@@ -1551,30 +2251,30 @@ function deleteGeneralPrComment(client, params) {
1551
2251
  }
1552
2252
 
1553
2253
  // src/features/analysis/scm/gitlab/gitlab.ts
1554
- import querystring from "node:querystring";
2254
+ import querystring2 from "node:querystring";
1555
2255
  import {
1556
2256
  Gitlab
1557
2257
  } from "@gitbeaker/rest";
1558
2258
  import { ProxyAgent } from "undici";
1559
- import { z as z5 } from "zod";
2259
+ import { z as z6 } from "zod";
1560
2260
 
1561
2261
  // src/features/analysis/scm/gitlab/types.ts
1562
- import { z as z4 } from "zod";
1563
- var GitlabAuthResultZ = z4.object({
1564
- access_token: z4.string(),
1565
- token_type: z4.string(),
1566
- refresh_token: z4.string()
2262
+ import { z as z5 } from "zod";
2263
+ var GitlabAuthResultZ = z5.object({
2264
+ access_token: z5.string(),
2265
+ token_type: z5.string(),
2266
+ refresh_token: z5.string()
1567
2267
  });
1568
2268
 
1569
2269
  // src/features/analysis/scm/gitlab/gitlab.ts
1570
- var EnvVariablesZod2 = z5.object({
1571
- GITLAB_API_TOKEN: z5.string().optional(),
1572
- BROKERED_HOSTS: z5.string().toLowerCase().transform(
2270
+ var EnvVariablesZod2 = z6.object({
2271
+ GITLAB_API_TOKEN: z6.string().optional(),
2272
+ BROKERED_HOSTS: z6.string().toLowerCase().transform(
1573
2273
  (x) => x.split(",").map((url) => url.trim(), []).filter(Boolean)
1574
2274
  ).default("")
1575
2275
  });
1576
2276
  var { GITLAB_API_TOKEN, BROKERED_HOSTS } = EnvVariablesZod2.parse(process.env);
1577
- function removeTrailingSlash2(str) {
2277
+ function removeTrailingSlash3(str) {
1578
2278
  return str.trim().replace(/\/+$/, "");
1579
2279
  }
1580
2280
  function getGitBeaker(options) {
@@ -1634,6 +2334,11 @@ async function getGitlabIsUserCollaborator({
1634
2334
  return false;
1635
2335
  }
1636
2336
  }
2337
+ var gitlabMergeRequestStatus = {
2338
+ merged: "merged",
2339
+ opened: "opened",
2340
+ closed: "closed"
2341
+ };
1637
2342
  async function getGitlabMergeRequestStatus({
1638
2343
  accessToken,
1639
2344
  repoUrl,
@@ -1643,9 +2348,9 @@ async function getGitlabMergeRequestStatus({
1643
2348
  const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
1644
2349
  const res = await api2.MergeRequests.show(projectPath, mrNumber);
1645
2350
  switch (res.state) {
1646
- case "merged" /* merged */:
1647
- case "opened" /* opened */:
1648
- case "closed" /* closed */:
2351
+ case gitlabMergeRequestStatus.merged:
2352
+ case gitlabMergeRequestStatus.opened:
2353
+ case gitlabMergeRequestStatus.closed:
1649
2354
  return res.state;
1650
2355
  default:
1651
2356
  throw new Error(`unknown merge request state ${res.state}`);
@@ -1798,7 +2503,7 @@ async function getGitlabReferenceData({ ref, gitlabUrl }, options) {
1798
2503
  throw new RefNotFoundError(`ref: ${ref} does not exist`);
1799
2504
  }
1800
2505
  function parseGitlabOwnerAndRepo(gitlabUrl) {
1801
- gitlabUrl = removeTrailingSlash2(gitlabUrl);
2506
+ gitlabUrl = removeTrailingSlash3(gitlabUrl);
1802
2507
  const parsingResult = parseScmURL(gitlabUrl, "GitLab" /* GitLab */);
1803
2508
  if (!parsingResult || !parsingResult.repoName) {
1804
2509
  throw new InvalidUrlPatternError(`invalid gitlab repo Url ${gitlabUrl}`);
@@ -1864,84 +2569,84 @@ import parseDiff from "parse-diff";
1864
2569
  import path3 from "path";
1865
2570
  import { simpleGit as simpleGit2 } from "simple-git";
1866
2571
  import tmp from "tmp";
1867
- import { z as z7 } from "zod";
2572
+ import { z as z8 } from "zod";
1868
2573
 
1869
2574
  // src/features/analysis/scm/scmSubmit/types.ts
1870
- import { z as z6 } from "zod";
1871
- var BaseSubmitToScmMessageZ = z6.object({
1872
- submitFixRequestId: z6.string().uuid(),
1873
- fixes: z6.array(
1874
- z6.object({
1875
- fixId: z6.string().uuid(),
1876
- diff: z6.string()
2575
+ import { z as z7 } from "zod";
2576
+ var BaseSubmitToScmMessageZ = z7.object({
2577
+ submitFixRequestId: z7.string().uuid(),
2578
+ fixes: z7.array(
2579
+ z7.object({
2580
+ fixId: z7.string().uuid(),
2581
+ diff: z7.string()
1877
2582
  })
1878
2583
  ),
1879
- commitHash: z6.string(),
1880
- repoUrl: z6.string()
2584
+ commitHash: z7.string(),
2585
+ repoUrl: z7.string()
1881
2586
  });
1882
2587
  var submitToScmMessageType = {
1883
2588
  commitToSameBranch: "commitToSameBranch",
1884
2589
  submitFixesForDifferentBranch: "submitFixesForDifferentBranch"
1885
2590
  };
1886
2591
  var CommitToSameBranchParamsZ = BaseSubmitToScmMessageZ.merge(
1887
- z6.object({
1888
- type: z6.literal(submitToScmMessageType.commitToSameBranch),
1889
- branch: z6.string(),
1890
- commitMessage: z6.string(),
1891
- commitDescription: z6.string().nullish(),
1892
- githubCommentId: z6.number().nullish()
2592
+ z7.object({
2593
+ type: z7.literal(submitToScmMessageType.commitToSameBranch),
2594
+ branch: z7.string(),
2595
+ commitMessage: z7.string(),
2596
+ commitDescription: z7.string().nullish(),
2597
+ githubCommentId: z7.number().nullish()
1893
2598
  })
1894
2599
  );
1895
- var SubmitFixesToDifferentBranchParamsZ = z6.object({
1896
- type: z6.literal(submitToScmMessageType.submitFixesForDifferentBranch),
1897
- submitBranch: z6.string(),
1898
- baseBranch: z6.string()
2600
+ var SubmitFixesToDifferentBranchParamsZ = z7.object({
2601
+ type: z7.literal(submitToScmMessageType.submitFixesForDifferentBranch),
2602
+ submitBranch: z7.string(),
2603
+ baseBranch: z7.string()
1899
2604
  }).merge(BaseSubmitToScmMessageZ);
1900
- var SubmitFixesMessageZ = z6.union([
2605
+ var SubmitFixesMessageZ = z7.union([
1901
2606
  CommitToSameBranchParamsZ,
1902
2607
  SubmitFixesToDifferentBranchParamsZ
1903
2608
  ]);
1904
- var FixResponseArrayZ = z6.array(
1905
- z6.object({
1906
- fixId: z6.string().uuid()
2609
+ var FixResponseArrayZ = z7.array(
2610
+ z7.object({
2611
+ fixId: z7.string().uuid()
1907
2612
  })
1908
2613
  );
1909
- var SubmitFixesBaseResponseMessageZ = z6.object({
1910
- submitFixRequestId: z6.string().uuid(),
1911
- submitBranches: z6.array(
1912
- z6.object({
1913
- branchName: z6.string(),
2614
+ var SubmitFixesBaseResponseMessageZ = z7.object({
2615
+ submitFixRequestId: z7.string().uuid(),
2616
+ submitBranches: z7.array(
2617
+ z7.object({
2618
+ branchName: z7.string(),
1914
2619
  fixes: FixResponseArrayZ
1915
2620
  })
1916
2621
  ),
1917
- error: z6.object({
1918
- type: z6.enum([
2622
+ error: z7.object({
2623
+ type: z7.enum([
1919
2624
  "InitialRepoAccessError",
1920
2625
  "PushBranchError",
1921
2626
  "UnknownError"
1922
2627
  ]),
1923
- info: z6.object({
1924
- message: z6.string(),
1925
- pushBranchName: z6.string().optional()
2628
+ info: z7.object({
2629
+ message: z7.string(),
2630
+ pushBranchName: z7.string().optional()
1926
2631
  })
1927
2632
  }).optional()
1928
2633
  });
1929
- var SubmitFixesToSameBranchResponseMessageZ = z6.object({
1930
- type: z6.literal(submitToScmMessageType.commitToSameBranch),
1931
- githubCommentId: z6.number().nullish()
2634
+ var SubmitFixesToSameBranchResponseMessageZ = z7.object({
2635
+ type: z7.literal(submitToScmMessageType.commitToSameBranch),
2636
+ githubCommentId: z7.number().nullish()
1932
2637
  }).merge(SubmitFixesBaseResponseMessageZ);
1933
- var SubmitFixesToDifferentBranchResponseMessageZ = z6.object({
1934
- type: z6.literal(submitToScmMessageType.submitFixesForDifferentBranch),
1935
- githubCommentId: z6.number().optional()
2638
+ var SubmitFixesToDifferentBranchResponseMessageZ = z7.object({
2639
+ type: z7.literal(submitToScmMessageType.submitFixesForDifferentBranch),
2640
+ githubCommentId: z7.number().optional()
1936
2641
  }).merge(SubmitFixesBaseResponseMessageZ);
1937
- var SubmitFixesResponseMessageZ = z6.discriminatedUnion("type", [
2642
+ var SubmitFixesResponseMessageZ = z7.discriminatedUnion("type", [
1938
2643
  SubmitFixesToSameBranchResponseMessageZ,
1939
2644
  SubmitFixesToDifferentBranchResponseMessageZ
1940
2645
  ]);
1941
2646
 
1942
2647
  // src/features/analysis/scm/scmSubmit/index.ts
1943
- var EnvVariablesZod3 = z7.object({
1944
- BROKERED_HOSTS: z7.string().toLowerCase().transform(
2648
+ var EnvVariablesZod3 = z8.object({
2649
+ BROKERED_HOSTS: z8.string().toLowerCase().transform(
1945
2650
  (x) => x.split(",").map((url) => url.trim(), []).filter(Boolean)
1946
2651
  ).default("")
1947
2652
  });
@@ -1958,49 +2663,59 @@ var isValidBranchName = async (branchName) => {
1958
2663
  return false;
1959
2664
  }
1960
2665
  };
1961
- var FixesZ = z7.array(z7.object({ fixId: z7.string(), diff: z7.string() })).nonempty();
2666
+ var FixesZ = z8.array(z8.object({ fixId: z8.string(), diff: z8.string() })).nonempty();
1962
2667
 
1963
2668
  // src/features/analysis/scm/scm.ts
2669
+ var GetRefererenceResultZ = z9.object({
2670
+ date: z9.date().optional(),
2671
+ sha: z9.string(),
2672
+ type: z9.nativeEnum(ReferenceType)
2673
+ });
1964
2674
  function getCloudScmLibTypeFromUrl(url) {
1965
2675
  if (!url) {
1966
2676
  return void 0;
1967
2677
  }
1968
2678
  const urlObject = new URL(url);
1969
2679
  const hostname = urlObject.hostname.toLowerCase();
1970
- if (hostname === "gitlab.com") {
2680
+ if (hostname === scmCloudHostname.GitLab) {
1971
2681
  return "GITLAB" /* GITLAB */;
1972
2682
  }
1973
- if (hostname === "github.com") {
2683
+ if (hostname === scmCloudHostname.GitHub) {
1974
2684
  return "GITHUB" /* GITHUB */;
1975
2685
  }
1976
- if (hostname === "dev.azure.com" || hostname.endsWith(".visualstudio.com")) {
2686
+ if (hostname === scmCloudHostname.Ado || hostname.endsWith(".visualstudio.com")) {
1977
2687
  return "ADO" /* ADO */;
1978
2688
  }
2689
+ if (hostname === scmCloudHostname.Bitbucket) {
2690
+ return "BITBUCKET" /* BITBUCKET */;
2691
+ }
1979
2692
  return void 0;
1980
2693
  }
2694
+ var scmCloudHostname = {
2695
+ GitLab: new URL(scmCloudUrl.GitLab).hostname,
2696
+ GitHub: new URL(scmCloudUrl.GitHub).hostname,
2697
+ Ado: new URL(scmCloudUrl.Ado).hostname,
2698
+ Bitbucket: new URL(scmCloudUrl.Bitbucket).hostname
2699
+ };
2700
+ var scmLibScmTypeToScmType = {
2701
+ ["GITLAB" /* GITLAB */]: "GitLab" /* GitLab */,
2702
+ ["GITHUB" /* GITHUB */]: "GitHub" /* GitHub */,
2703
+ ["ADO" /* ADO */]: "Ado" /* Ado */,
2704
+ ["BITBUCKET" /* BITBUCKET */]: "Bitbucket" /* Bitbucket */
2705
+ };
2706
+ var scmTypeToScmLibScmType = {
2707
+ ["GitLab" /* GitLab */]: "GITLAB" /* GITLAB */,
2708
+ ["GitHub" /* GitHub */]: "GITHUB" /* GITHUB */,
2709
+ ["Ado" /* Ado */]: "ADO" /* ADO */,
2710
+ ["Bitbucket" /* Bitbucket */]: "BITBUCKET" /* BITBUCKET */
2711
+ };
1981
2712
  function getScmTypeFromScmLibType(scmLibType) {
1982
- if (scmLibType === "GITLAB" /* GITLAB */) {
1983
- return "GitLab" /* GitLab */;
1984
- }
1985
- if (scmLibType === "GITHUB" /* GITHUB */) {
1986
- return "GitHub" /* GitHub */;
1987
- }
1988
- if (scmLibType === "ADO" /* ADO */) {
1989
- return "Ado" /* Ado */;
1990
- }
1991
- throw new Error(`unknown scm lib type: ${scmLibType}`);
2713
+ const parsedScmLibType = z9.nativeEnum(ScmLibScmType).parse(scmLibType);
2714
+ return scmLibScmTypeToScmType[parsedScmLibType];
1992
2715
  }
1993
2716
  function getScmLibTypeFromScmType(scmType) {
1994
- if (scmType === "GitLab" /* GitLab */) {
1995
- return "GITLAB" /* GITLAB */;
1996
- }
1997
- if (scmType === "GitHub" /* GitHub */) {
1998
- return "GITHUB" /* GITHUB */;
1999
- }
2000
- if (scmType === "Ado" /* Ado */) {
2001
- return "ADO" /* ADO */;
2002
- }
2003
- throw new Error(`unknown scm type: ${scmType}`);
2717
+ const parsedScmType = z9.nativeEnum(ScmType).parse(scmType);
2718
+ return scmTypeToScmLibScmType[parsedScmType];
2004
2719
  }
2005
2720
  function getScmConfig({
2006
2721
  url,
@@ -2096,6 +2811,19 @@ var RepoNoTokenAccessError = class extends Error {
2096
2811
  super(m);
2097
2812
  }
2098
2813
  };
2814
+ function buildAuthrizedRepoUrl(args) {
2815
+ const { url, username, password } = args;
2816
+ const is_http = url.toLowerCase().startsWith("http://");
2817
+ const is_https = url.toLowerCase().startsWith("https://");
2818
+ if (is_http) {
2819
+ return `http://${username}:${password}@${url.toLowerCase().replace("http://", "")}`;
2820
+ } else if (is_https) {
2821
+ return `https://${username}:${password}@${url.toLowerCase().replace("https://", "")}`;
2822
+ } else {
2823
+ console.error(`invalid scm url ${url}`);
2824
+ throw new Error(`invalid scm url ${url}`);
2825
+ }
2826
+ }
2099
2827
  var SCMLib = class {
2100
2828
  constructor(url, accessToken, scmOrg) {
2101
2829
  __publicField(this, "url");
@@ -2111,24 +2839,45 @@ var SCMLib = class {
2111
2839
  throw new Error("no url");
2112
2840
  }
2113
2841
  const trimmedUrl = this.url.trim().replace(/\/$/, "");
2114
- if (!this.accessToken) {
2842
+ const accessToken = this.getAccessToken();
2843
+ if (!accessToken) {
2115
2844
  return trimmedUrl;
2116
2845
  }
2846
+ console.log(
2847
+ "this instanceof BitbucketSCMLib",
2848
+ this instanceof BitbucketSCMLib
2849
+ );
2117
2850
  const scmLibType = this.getScmLibType();
2118
2851
  if (scmLibType === "ADO" /* ADO */) {
2119
- return `https://${this.accessToken}@${trimmedUrl.toLowerCase().replace("https://", "")}`;
2852
+ return `https://${accessToken}@${trimmedUrl.toLowerCase().replace("https://", "")}`;
2120
2853
  }
2121
- const is_http = trimmedUrl.toLowerCase().startsWith("http://");
2122
- const is_https = trimmedUrl.toLowerCase().startsWith("https://");
2123
- const username = await this._getUsernameForAuthUrl();
2124
- if (is_http) {
2125
- return `http://${username}:${this.accessToken}@${trimmedUrl.toLowerCase().replace("http://", "")}`;
2126
- } else if (is_https) {
2127
- return `https://${username}:${this.accessToken}@${trimmedUrl.toLowerCase().replace("https://", "")}`;
2128
- } else {
2129
- console.error(`invalid scm url ${trimmedUrl}`);
2130
- throw new Error(`invalid scm url ${trimmedUrl}`);
2854
+ if (this instanceof BitbucketSCMLib) {
2855
+ const authData = this.getAuthData();
2856
+ switch (authData.authType) {
2857
+ case "public": {
2858
+ return trimmedUrl;
2859
+ }
2860
+ case "token": {
2861
+ const { token } = authData;
2862
+ const username2 = await this._getUsernameForAuthUrl();
2863
+ return buildAuthrizedRepoUrl({
2864
+ url: trimmedUrl,
2865
+ username: username2,
2866
+ password: token
2867
+ });
2868
+ }
2869
+ case "basic": {
2870
+ const { username: username2, password } = authData;
2871
+ return buildAuthrizedRepoUrl({ url: trimmedUrl, username: username2, password });
2872
+ }
2873
+ }
2131
2874
  }
2875
+ const username = await this._getUsernameForAuthUrl();
2876
+ return buildAuthrizedRepoUrl({
2877
+ url: trimmedUrl,
2878
+ username,
2879
+ password: accessToken
2880
+ });
2132
2881
  }
2133
2882
  getAccessToken() {
2134
2883
  return this.accessToken || "";
@@ -2142,6 +2891,12 @@ var SCMLib = class {
2142
2891
  }
2143
2892
  return this.url.split("/").at(-1) || "";
2144
2893
  }
2894
+ _validateToken() {
2895
+ if (!this.accessToken) {
2896
+ console.error("no access token");
2897
+ throw new Error("no access token");
2898
+ }
2899
+ }
2145
2900
  static async getIsValidBranchName(branchName) {
2146
2901
  return isValidBranchName(branchName);
2147
2902
  }
@@ -2156,20 +2911,27 @@ var SCMLib = class {
2156
2911
  trimmedUrl = url.trim().replace(/\/$/, "").replace(/.git$/i, "");
2157
2912
  }
2158
2913
  try {
2159
- if ("GITHUB" /* GITHUB */ === scmType) {
2160
- const scm = new GithubSCMLib(trimmedUrl, accessToken, scmOrg);
2161
- await scm.validateParams();
2162
- return scm;
2163
- }
2164
- if ("GITLAB" /* GITLAB */ === scmType) {
2165
- const scm = new GitlabSCMLib(trimmedUrl, accessToken, scmOrg);
2166
- await scm.validateParams();
2167
- return scm;
2168
- }
2169
- if ("ADO" /* ADO */ === scmType) {
2170
- const scm = new AdoSCMLib(trimmedUrl, accessToken, scmOrg);
2171
- await scm.validateParams();
2172
- return scm;
2914
+ switch (scmType) {
2915
+ case "GITHUB" /* GITHUB */: {
2916
+ const scm = new GithubSCMLib(trimmedUrl, accessToken, scmOrg);
2917
+ await scm.validateParams();
2918
+ return scm;
2919
+ }
2920
+ case "GITLAB" /* GITLAB */: {
2921
+ const scm = new GitlabSCMLib(trimmedUrl, accessToken, scmOrg);
2922
+ await scm.validateParams();
2923
+ return scm;
2924
+ }
2925
+ case "ADO" /* ADO */: {
2926
+ const scm = new AdoSCMLib(trimmedUrl, accessToken, scmOrg);
2927
+ await scm.validateParams();
2928
+ return scm;
2929
+ }
2930
+ case "BITBUCKET" /* BITBUCKET */: {
2931
+ const scm = new BitbucketSCMLib(trimmedUrl, accessToken, scmOrg);
2932
+ await scm.validateParams();
2933
+ return scm;
2934
+ }
2173
2935
  }
2174
2936
  } catch (e) {
2175
2937
  if (e instanceof InvalidRepoUrlError && url) {
@@ -2180,36 +2942,24 @@ var SCMLib = class {
2180
2942
  }
2181
2943
  _validateAccessTokenAndUrl() {
2182
2944
  if (!this.accessToken) {
2945
+ console.error("no access token");
2183
2946
  throw new InvalidAccessTokenError("no access token");
2184
2947
  }
2948
+ this._validateUrl();
2949
+ }
2950
+ _validateUrl() {
2185
2951
  if (!this.url) {
2952
+ console.error("no url");
2186
2953
  throw new InvalidRepoUrlError("no url");
2187
2954
  }
2188
2955
  }
2189
2956
  };
2190
2957
  var AdoSCMLib = class extends SCMLib {
2191
- updatePrComment(_params, _oktokit) {
2192
- throw new Error("updatePrComment not implemented.");
2193
- }
2194
- getPrComment(_commentId) {
2195
- throw new Error("getPrComment not implemented.");
2196
- }
2197
- async forkRepo() {
2198
- throw new Error("forkRepo not supported yet");
2199
- }
2200
- async createOrUpdateRepositorySecret() {
2201
- throw new Error("createOrUpdateRepositorySecret not supported yet");
2202
- }
2203
- async createPullRequestWithNewFile(_sourceRepoUrl, _filesPaths, _userRepoUrl, _title, _body) {
2204
- throw new Error("createPullRequestWithNewFile not supported yet");
2205
- }
2206
- async createSubmitRequest(targetBranchName, sourceBranchName, title, body) {
2207
- if (!this.accessToken || !this.url) {
2208
- console.error("no access token or no url");
2209
- throw new Error("no access token or no url");
2210
- }
2958
+ async createSubmitRequest(params) {
2959
+ this._validateAccessTokenAndUrl();
2960
+ const { targetBranchName, sourceBranchName, title, body } = params;
2211
2961
  return String(
2212
- await createAdoPullRequest({
2962
+ await AdoSdk.createAdoPullRequest({
2213
2963
  title,
2214
2964
  body,
2215
2965
  targetBranchName,
@@ -2221,7 +2971,7 @@ var AdoSCMLib = class extends SCMLib {
2221
2971
  );
2222
2972
  }
2223
2973
  async validateParams() {
2224
- return adoValidateParams({
2974
+ return AdoSdk.adoValidateParams({
2225
2975
  url: this.url,
2226
2976
  accessToken: this.accessToken,
2227
2977
  tokenOrg: this.scmOrg
@@ -2232,18 +2982,15 @@ var AdoSCMLib = class extends SCMLib {
2232
2982
  console.error("no access token");
2233
2983
  throw new Error("no access token");
2234
2984
  }
2235
- return getAdoRepoList({
2985
+ return AdoSdk.getAdoRepoList({
2236
2986
  orgName: scmOrg,
2237
2987
  tokenOrg: this.scmOrg,
2238
2988
  accessToken: this.accessToken
2239
2989
  });
2240
2990
  }
2241
2991
  async getBranchList() {
2242
- if (!this.accessToken || !this.url) {
2243
- console.error("no access token or no url");
2244
- throw new Error("no access token or no url");
2245
- }
2246
- return getAdoBranchList({
2992
+ this._validateAccessTokenAndUrl();
2993
+ return AdoSdk.getAdoBranchList({
2247
2994
  accessToken: this.accessToken,
2248
2995
  tokenOrg: this.scmOrg,
2249
2996
  repoUrl: this.url
@@ -2254,7 +3001,7 @@ var AdoSCMLib = class extends SCMLib {
2254
3001
  }
2255
3002
  getAuthHeaders() {
2256
3003
  if (this.accessToken) {
2257
- if (getAdoTokenType(this.accessToken) === "OAUTH" /* OAUTH */) {
3004
+ if (AdoSdk.getAdoTokenType(this.accessToken) === "OAUTH" /* OAUTH */) {
2258
3005
  return {
2259
3006
  authorization: `Bearer ${this.accessToken}`
2260
3007
  };
@@ -2269,21 +3016,17 @@ var AdoSCMLib = class extends SCMLib {
2269
3016
  return {};
2270
3017
  }
2271
3018
  getDownloadUrl(sha) {
2272
- if (!this.url) {
2273
- console.error("no url");
2274
- throw new Error("no url");
2275
- }
2276
- return getAdoDownloadUrl({ repoUrl: this.url, branch: sha });
3019
+ this._validateUrl();
3020
+ return Promise.resolve(
3021
+ AdoSdk.getAdoDownloadUrl({ repoUrl: this.url, branch: sha })
3022
+ );
2277
3023
  }
2278
3024
  async _getUsernameForAuthUrl() {
2279
3025
  throw new Error("_getUsernameForAuthUrl() is not relevant for ADO");
2280
3026
  }
2281
3027
  async getIsRemoteBranch(branch) {
2282
- if (!this.accessToken || !this.url) {
2283
- console.error("no access token or no url");
2284
- throw new Error("no access token or no url");
2285
- }
2286
- return getAdoIsRemoteBranch({
3028
+ this._validateAccessTokenAndUrl();
3029
+ return AdoSdk.getAdoIsRemoteBranch({
2287
3030
  accessToken: this.accessToken,
2288
3031
  tokenOrg: this.scmOrg,
2289
3032
  repoUrl: this.url,
@@ -2291,11 +3034,8 @@ var AdoSCMLib = class extends SCMLib {
2291
3034
  });
2292
3035
  }
2293
3036
  async getUserHasAccessToRepo() {
2294
- if (!this.accessToken || !this.url) {
2295
- console.error("no access token or no url");
2296
- throw new Error("no access token or no url");
2297
- }
2298
- return getAdoIsUserCollaborator({
3037
+ this._validateAccessTokenAndUrl();
3038
+ return AdoSdk.getAdoIsUserCollaborator({
2299
3039
  accessToken: this.accessToken,
2300
3040
  tokenOrg: this.scmOrg,
2301
3041
  repoUrl: this.url
@@ -2305,11 +3045,8 @@ var AdoSCMLib = class extends SCMLib {
2305
3045
  throw new Error("getUsername() is not relevant for ADO");
2306
3046
  }
2307
3047
  async getSubmitRequestStatus(scmSubmitRequestId) {
2308
- if (!this.accessToken || !this.url) {
2309
- console.error("no access token or no url");
2310
- throw new Error("no access token or no url");
2311
- }
2312
- const state = await getAdoPullRequestStatus({
3048
+ this._validateAccessTokenAndUrl();
3049
+ const state = await AdoSdk.getAdoPullRequestStatus({
2313
3050
  accessToken: this.accessToken,
2314
3051
  tokenOrg: this.scmOrg,
2315
3052
  repoUrl: this.url,
@@ -2317,24 +3054,21 @@ var AdoSCMLib = class extends SCMLib {
2317
3054
  });
2318
3055
  switch (state) {
2319
3056
  case "completed" /* completed */:
2320
- return "MERGED" /* MERGED */;
3057
+ return "merged";
2321
3058
  case "active" /* active */:
2322
- return "OPEN" /* OPEN */;
3059
+ return "open";
2323
3060
  case "abandoned" /* abandoned */:
2324
- return "CLOSED" /* CLOSED */;
3061
+ return "closed";
2325
3062
  default:
2326
3063
  throw new Error(`unknown state ${state}`);
2327
3064
  }
2328
3065
  }
2329
3066
  async getRepoBlameRanges(_ref, _path) {
2330
- return await getAdoBlameRanges();
3067
+ return await AdoSdk.getAdoBlameRanges();
2331
3068
  }
2332
3069
  async getReferenceData(ref) {
2333
- if (!this.url) {
2334
- console.error("no url");
2335
- throw new Error("no url");
2336
- }
2337
- return await getAdoReferenceData({
3070
+ this._validateUrl();
3071
+ return await AdoSdk.getAdoReferenceData({
2338
3072
  ref,
2339
3073
  repoUrl: this.url,
2340
3074
  accessToken: this.accessToken,
@@ -2342,11 +3076,8 @@ var AdoSCMLib = class extends SCMLib {
2342
3076
  });
2343
3077
  }
2344
3078
  async getRepoDefaultBranch() {
2345
- if (!this.url) {
2346
- console.error("no url");
2347
- throw new Error("no url");
2348
- }
2349
- return await getAdoRepoDefaultBranch({
3079
+ this._validateUrl();
3080
+ return await AdoSdk.getAdoRepoDefaultBranch({
2350
3081
  repoUrl: this.url,
2351
3082
  tokenOrg: this.scmOrg,
2352
3083
  accessToken: this.accessToken
@@ -2356,22 +3087,11 @@ var AdoSCMLib = class extends SCMLib {
2356
3087
  this._validateAccessTokenAndUrl();
2357
3088
  return Promise.resolve(getAdoPrUrl({ prNumber, url: this.url }));
2358
3089
  }
2359
- postGeneralPrComment() {
2360
- throw new Error("Method not implemented.");
2361
- }
2362
- getGeneralPrComments() {
2363
- throw new Error("Method not implemented.");
2364
- }
2365
- deleteGeneralPrComment() {
2366
- throw new Error("Method not implemented.");
2367
- }
2368
3090
  };
2369
3091
  var GitlabSCMLib = class extends SCMLib {
2370
- async createSubmitRequest(targetBranchName, sourceBranchName, title, body) {
2371
- if (!this.accessToken || !this.url) {
2372
- console.error("no access token or no url");
2373
- throw new Error("no access token or no url");
2374
- }
3092
+ async createSubmitRequest(params) {
3093
+ this._validateAccessTokenAndUrl();
3094
+ const { targetBranchName, sourceBranchName, title, body } = params;
2375
3095
  return String(
2376
3096
  await createMergeRequest({
2377
3097
  title,
@@ -2389,23 +3109,6 @@ var GitlabSCMLib = class extends SCMLib {
2389
3109
  accessToken: this.accessToken
2390
3110
  });
2391
3111
  }
2392
- async forkRepo() {
2393
- if (!this.accessToken) {
2394
- console.error("no access token");
2395
- throw new Error("no access token");
2396
- }
2397
- throw new Error("not supported yet");
2398
- }
2399
- async createOrUpdateRepositorySecret() {
2400
- if (!this.accessToken) {
2401
- console.error("no access token");
2402
- throw new Error("no access token");
2403
- }
2404
- throw new Error("not supported yet");
2405
- }
2406
- async createPullRequestWithNewFile(_sourceRepoUrl, _filesPaths, _userRepoUrl, _title, _body) {
2407
- throw new Error("not implemented");
2408
- }
2409
3112
  async getRepoList(_scmOrg) {
2410
3113
  if (!this.accessToken) {
2411
3114
  console.error("no access token");
@@ -2414,10 +3117,7 @@ var GitlabSCMLib = class extends SCMLib {
2414
3117
  return getGitlabRepoList(this.url, this.accessToken);
2415
3118
  }
2416
3119
  async getBranchList() {
2417
- if (!this.accessToken || !this.url) {
2418
- console.error("no access token or no url");
2419
- throw new Error("no access token or no url");
2420
- }
3120
+ this._validateAccessTokenAndUrl();
2421
3121
  return getGitlabBranchList({
2422
3122
  accessToken: this.accessToken,
2423
3123
  repoUrl: this.url
@@ -2438,7 +3138,9 @@ var GitlabSCMLib = class extends SCMLib {
2438
3138
  getDownloadUrl(sha) {
2439
3139
  const urlSplit = this.url?.split("/") || [];
2440
3140
  const repoName = urlSplit[urlSplit?.length - 1];
2441
- return `${this.url}/-/archive/${sha}/${repoName}-${sha}.zip`;
3141
+ return Promise.resolve(
3142
+ `${this.url}/-/archive/${sha}/${repoName}-${sha}.zip`
3143
+ );
2442
3144
  }
2443
3145
  async _getUsernameForAuthUrl() {
2444
3146
  if (this?.accessToken?.startsWith("glpat-")) {
@@ -2448,10 +3150,7 @@ var GitlabSCMLib = class extends SCMLib {
2448
3150
  }
2449
3151
  }
2450
3152
  async getIsRemoteBranch(branch) {
2451
- if (!this.accessToken || !this.url) {
2452
- console.error("no access token or no url");
2453
- throw new Error("no access token or no url");
2454
- }
3153
+ this._validateAccessTokenAndUrl();
2455
3154
  return getGitlabIsRemoteBranch({
2456
3155
  accessToken: this.accessToken,
2457
3156
  repoUrl: this.url,
@@ -2459,10 +3158,7 @@ var GitlabSCMLib = class extends SCMLib {
2459
3158
  });
2460
3159
  }
2461
3160
  async getUserHasAccessToRepo() {
2462
- if (!this.accessToken || !this.url) {
2463
- console.error("no access token or no url");
2464
- throw new Error("no access token or no url");
2465
- }
3161
+ this._validateAccessTokenAndUrl();
2466
3162
  const username = await this.getUsername();
2467
3163
  return getGitlabIsUserCollaborator({
2468
3164
  username,
@@ -2471,38 +3167,29 @@ var GitlabSCMLib = class extends SCMLib {
2471
3167
  });
2472
3168
  }
2473
3169
  async getUsername() {
2474
- if (!this.accessToken) {
2475
- console.error("no access token");
2476
- throw new Error("no access token");
2477
- }
2478
- return getGitlabUsername(this.url, this.accessToken);
2479
- }
2480
- async getSubmitRequestStatus(scmSubmitRequestId) {
2481
- if (!this.accessToken || !this.url) {
2482
- console.error("no access token or no url");
2483
- throw new Error("no access token or no url");
2484
- }
3170
+ this._validateAccessTokenAndUrl();
3171
+ return getGitlabUsername(this.url, this.accessToken);
3172
+ }
3173
+ async getSubmitRequestStatus(scmSubmitRequestId) {
3174
+ this._validateAccessTokenAndUrl();
2485
3175
  const state = await getGitlabMergeRequestStatus({
2486
3176
  accessToken: this.accessToken,
2487
3177
  repoUrl: this.url,
2488
3178
  mrNumber: Number(scmSubmitRequestId)
2489
3179
  });
2490
3180
  switch (state) {
2491
- case "merged" /* merged */:
2492
- return "MERGED" /* MERGED */;
2493
- case "opened" /* opened */:
2494
- return "OPEN" /* OPEN */;
2495
- case "closed" /* closed */:
2496
- return "CLOSED" /* CLOSED */;
3181
+ case gitlabMergeRequestStatus.merged:
3182
+ return "merged";
3183
+ case gitlabMergeRequestStatus.opened:
3184
+ return "open";
3185
+ case gitlabMergeRequestStatus.closed:
3186
+ return "closed";
2497
3187
  default:
2498
3188
  throw new Error(`unknown state ${state}`);
2499
3189
  }
2500
3190
  }
2501
3191
  async getRepoBlameRanges(ref, path9) {
2502
- if (!this.url) {
2503
- console.error("no url");
2504
- throw new Error("no url");
2505
- }
3192
+ this._validateUrl();
2506
3193
  return await getGitlabBlameRanges(
2507
3194
  { ref, path: path9, gitlabUrl: this.url },
2508
3195
  {
@@ -2512,10 +3199,7 @@ var GitlabSCMLib = class extends SCMLib {
2512
3199
  );
2513
3200
  }
2514
3201
  async getReferenceData(ref) {
2515
- if (!this.url) {
2516
- console.error("no url");
2517
- throw new Error("no url");
2518
- }
3202
+ this._validateUrl();
2519
3203
  return await getGitlabReferenceData(
2520
3204
  { ref, gitlabUrl: this.url },
2521
3205
  {
@@ -2525,21 +3209,12 @@ var GitlabSCMLib = class extends SCMLib {
2525
3209
  );
2526
3210
  }
2527
3211
  async getRepoDefaultBranch() {
2528
- if (!this.url) {
2529
- console.error("no url");
2530
- throw new Error("no url");
2531
- }
3212
+ this._validateUrl();
2532
3213
  return await getGitlabRepoDefaultBranch(this.url, {
2533
3214
  url: this.url,
2534
3215
  gitlabAuthToken: this.accessToken
2535
3216
  });
2536
3217
  }
2537
- getPrComment(_commentId) {
2538
- throw new Error("getPrComment not implemented.");
2539
- }
2540
- updatePrComment(_params, _oktokit) {
2541
- throw new Error("updatePrComment not implemented.");
2542
- }
2543
3218
  async getPrUrl(prNumber) {
2544
3219
  this._validateAccessTokenAndUrl();
2545
3220
  const res = await getGitlabMergeRequest({
@@ -2549,15 +3224,6 @@ var GitlabSCMLib = class extends SCMLib {
2549
3224
  });
2550
3225
  return res.web_url;
2551
3226
  }
2552
- postGeneralPrComment() {
2553
- throw new Error("Method not implemented.");
2554
- }
2555
- getGeneralPrComments() {
2556
- throw new Error("Method not implemented.");
2557
- }
2558
- deleteGeneralPrComment() {
2559
- throw new Error("Method not implemented.");
2560
- }
2561
3227
  };
2562
3228
  var GithubSCMLib = class extends SCMLib {
2563
3229
  // we don't always need a url, what's important is that we have an access token
@@ -2566,11 +3232,9 @@ var GithubSCMLib = class extends SCMLib {
2566
3232
  __publicField(this, "oktokit");
2567
3233
  this.oktokit = new Octokit2({ auth: accessToken });
2568
3234
  }
2569
- async createSubmitRequest(targetBranchName, sourceBranchName, title, body) {
2570
- if (!this.accessToken || !this.url) {
2571
- console.error("no access token or no url");
2572
- throw new Error("no access token or no url");
2573
- }
3235
+ async createSubmitRequest(params) {
3236
+ this._validateAccessTokenAndUrl();
3237
+ const { targetBranchName, sourceBranchName, title, body } = params;
2574
3238
  return String(
2575
3239
  await createPullRequest({
2576
3240
  title,
@@ -2583,10 +3247,7 @@ var GithubSCMLib = class extends SCMLib {
2583
3247
  );
2584
3248
  }
2585
3249
  async forkRepo(repoUrl) {
2586
- if (!this.accessToken) {
2587
- console.error("no access token");
2588
- throw new Error("no access token");
2589
- }
3250
+ this._validateToken();
2590
3251
  return forkRepo({
2591
3252
  repoUrl,
2592
3253
  accessToken: this.accessToken
@@ -2692,7 +3353,7 @@ var GithubSCMLib = class extends SCMLib {
2692
3353
  owner,
2693
3354
  repo
2694
3355
  });
2695
- return z8.string().parse(prRes.data);
3356
+ return z9.string().parse(prRes.data);
2696
3357
  }
2697
3358
  async getRepoList(_scmOrg) {
2698
3359
  if (!this.accessToken) {
@@ -2702,10 +3363,7 @@ var GithubSCMLib = class extends SCMLib {
2702
3363
  return getGithubRepoList(this.accessToken);
2703
3364
  }
2704
3365
  async getBranchList() {
2705
- if (!this.accessToken || !this.url) {
2706
- console.error("no access token or no url");
2707
- throw new Error("no access token or no url");
2708
- }
3366
+ this._validateAccessTokenAndUrl();
2709
3367
  return getGithubBranchList(this.accessToken, this.url);
2710
3368
  }
2711
3369
  getScmLibType() {
@@ -2718,16 +3376,13 @@ var GithubSCMLib = class extends SCMLib {
2718
3376
  return {};
2719
3377
  }
2720
3378
  getDownloadUrl(sha) {
2721
- return `${this.url}/zipball/${sha}`;
3379
+ return Promise.resolve(`${this.url}/zipball/${sha}`);
2722
3380
  }
2723
3381
  async _getUsernameForAuthUrl() {
2724
3382
  return this.getUsername();
2725
3383
  }
2726
3384
  async getIsRemoteBranch(branch) {
2727
- if (!this.accessToken || !this.url) {
2728
- console.error("no access token or no url");
2729
- throw new Error("no access token or no url");
2730
- }
3385
+ this._validateAccessTokenAndUrl();
2731
3386
  return getGithubIsRemoteBranch(this.accessToken, this.url, branch);
2732
3387
  }
2733
3388
  async getUserHasAccessToRepo() {
@@ -2755,25 +3410,10 @@ var GithubSCMLib = class extends SCMLib {
2755
3410
  this.url,
2756
3411
  Number(scmSubmitRequestId)
2757
3412
  );
2758
- if (state === "merged") {
2759
- return "MERGED" /* MERGED */;
2760
- }
2761
- if (state === "open") {
2762
- return "OPEN" /* OPEN */;
2763
- }
2764
- if (state === "draft") {
2765
- return "DRAFT" /* DRAFT */;
2766
- }
2767
- if (state === "closed") {
2768
- return "CLOSED" /* CLOSED */;
2769
- }
2770
- throw new Error(`unknown state ${state}`);
3413
+ return state;
2771
3414
  }
2772
3415
  async getRepoBlameRanges(ref, path9) {
2773
- if (!this.url) {
2774
- console.error("no url");
2775
- throw new Error("no url");
2776
- }
3416
+ this._validateUrl();
2777
3417
  return await getGithubBlameRanges(
2778
3418
  { ref, path: path9, gitHubUrl: this.url },
2779
3419
  {
@@ -2782,10 +3422,7 @@ var GithubSCMLib = class extends SCMLib {
2782
3422
  );
2783
3423
  }
2784
3424
  async getReferenceData(ref) {
2785
- if (!this.url) {
2786
- console.error("no url");
2787
- throw new Error("no url");
2788
- }
3425
+ this._validateUrl();
2789
3426
  return await getGithubReferenceData(
2790
3427
  { ref, gitHubUrl: this.url },
2791
3428
  {
@@ -2794,10 +3431,7 @@ var GithubSCMLib = class extends SCMLib {
2794
3431
  );
2795
3432
  }
2796
3433
  async getPrComment(commentId) {
2797
- if (!this.url) {
2798
- console.error("no url");
2799
- throw new Error("no url");
2800
- }
3434
+ this._validateUrl();
2801
3435
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
2802
3436
  return await getPrComment(this.oktokit, {
2803
3437
  repo,
@@ -2806,10 +3440,7 @@ var GithubSCMLib = class extends SCMLib {
2806
3440
  });
2807
3441
  }
2808
3442
  async getRepoDefaultBranch() {
2809
- if (!this.url) {
2810
- console.error("no url");
2811
- throw new Error("no url");
2812
- }
3443
+ this._validateUrl();
2813
3444
  return await getGithubRepoDefaultBranch(this.url, {
2814
3445
  githubAuthToken: this.accessToken
2815
3446
  });
@@ -2829,10 +3460,7 @@ var GithubSCMLib = class extends SCMLib {
2829
3460
  }
2830
3461
  async postGeneralPrComment(params, auth) {
2831
3462
  const { prNumber, body } = params;
2832
- if (!this.url) {
2833
- console.error("no url");
2834
- throw new Error("no url");
2835
- }
3463
+ this._validateUrl();
2836
3464
  const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
2837
3465
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
2838
3466
  return await postGeneralPrComment(oktoKit, {
@@ -2844,10 +3472,7 @@ var GithubSCMLib = class extends SCMLib {
2844
3472
  }
2845
3473
  async getGeneralPrComments(params, auth) {
2846
3474
  const { prNumber } = params;
2847
- if (!this.url) {
2848
- console.error("no url");
2849
- throw new Error("no url");
2850
- }
3475
+ this._validateUrl();
2851
3476
  const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
2852
3477
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
2853
3478
  return await getGeneralPrComments(oktoKit, {
@@ -2857,10 +3482,7 @@ var GithubSCMLib = class extends SCMLib {
2857
3482
  });
2858
3483
  }
2859
3484
  async deleteGeneralPrComment({ commentId }, auth) {
2860
- if (!this.url) {
2861
- console.error("no url");
2862
- throw new Error("no url");
2863
- }
3485
+ this._validateUrl();
2864
3486
  const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
2865
3487
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
2866
3488
  return deleteGeneralPrComment(oktoKit, {
@@ -2871,7 +3493,7 @@ var GithubSCMLib = class extends SCMLib {
2871
3493
  }
2872
3494
  };
2873
3495
  var StubSCMLib = class extends SCMLib {
2874
- async createSubmitRequest(_targetBranchName, _sourceBranchName, _title, _body) {
3496
+ async createSubmitRequest(_params) {
2875
3497
  console.error("createSubmitRequest() not implemented");
2876
3498
  throw new Error("createSubmitRequest() not implemented");
2877
3499
  }
@@ -2887,10 +3509,6 @@ var StubSCMLib = class extends SCMLib {
2887
3509
  console.error("getDownloadUrl() not implemented");
2888
3510
  throw new Error("getDownloadUrl() not implemented");
2889
3511
  }
2890
- async _getUsernameForAuthUrl() {
2891
- console.error("_getUsernameForAuthUrl() not implemented");
2892
- throw new Error("_getUsernameForAuthUrl() not implemented");
2893
- }
2894
3512
  async getIsRemoteBranch(_branch) {
2895
3513
  console.error("getIsRemoteBranch() not implemented");
2896
3514
  throw new Error("getIsRemoteBranch() not implemented");
@@ -2899,18 +3517,6 @@ var StubSCMLib = class extends SCMLib {
2899
3517
  console.error("validateParams() not implemented");
2900
3518
  throw new Error("validateParams() not implemented");
2901
3519
  }
2902
- async forkRepo() {
2903
- console.error("forkRepo() not implemented");
2904
- throw new Error("forkRepo() not implemented");
2905
- }
2906
- async createOrUpdateRepositorySecret() {
2907
- console.error("forkRepo() not implemented");
2908
- throw new Error("forkRepo() not implemented");
2909
- }
2910
- async createPullRequestWithNewFile(_sourceRepoUrl, _filesPaths, _userRepoUrl, _title, _body) {
2911
- console.error("createPullRequestWithNewFile() not implemented");
2912
- throw new Error("createPullRequestWithNewFile() not implemented");
2913
- }
2914
3520
  async getRepoList(_scmOrg) {
2915
3521
  console.error("getRepoList() not implemented");
2916
3522
  throw new Error("getRepoList() not implemented");
@@ -2943,607 +3549,496 @@ var StubSCMLib = class extends SCMLib {
2943
3549
  console.error("getRepoDefaultBranch() not implemented");
2944
3550
  throw new Error("getRepoDefaultBranch() not implemented");
2945
3551
  }
2946
- async getPrComment(_commentId) {
2947
- console.error("getPrComment() not implemented");
2948
- throw new Error("getPrComment() not implemented");
2949
- }
2950
- async updatePrComment() {
2951
- console.error("updatePrComment() not implemented");
2952
- throw new Error("updatePrComment() not implemented");
2953
- }
2954
3552
  async getPrUrl(_prNumber) {
2955
3553
  console.error("getPr() not implemented");
2956
3554
  throw new Error("getPr() not implemented");
2957
3555
  }
2958
- postGeneralPrComment() {
2959
- throw new Error("Method not implemented.");
2960
- }
2961
- getGeneralPrComments() {
2962
- throw new Error("Method not implemented.");
2963
- }
2964
- deleteGeneralPrComment() {
3556
+ _getUsernameForAuthUrl() {
2965
3557
  throw new Error("Method not implemented.");
2966
3558
  }
2967
3559
  };
2968
-
2969
- // src/features/analysis/scm/ado.ts
2970
- function removeTrailingSlash3(str) {
2971
- return str.trim().replace(/\/+$/, "");
2972
- }
2973
- async function _getOrgsForOauthToken({ oauthToken }) {
2974
- const profileZ = z9.object({
2975
- displayName: z9.string(),
2976
- publicAlias: z9.string().min(1),
2977
- emailAddress: z9.string(),
2978
- coreRevision: z9.number(),
2979
- timeStamp: z9.string(),
2980
- id: z9.string(),
2981
- revision: z9.number()
2982
- });
2983
- const accountsZ = z9.object({
2984
- count: z9.number(),
2985
- value: z9.array(
2986
- z9.object({
2987
- accountId: z9.string(),
2988
- accountUri: z9.string(),
2989
- accountName: z9.string()
2990
- })
2991
- )
2992
- });
2993
- const profileRes = await fetch(
2994
- "https://app.vssps.visualstudio.com/_apis/profile/profiles/me?api-version=6.0",
2995
- {
2996
- method: "GET",
2997
- headers: {
2998
- Authorization: `Bearer ${oauthToken}`
2999
- }
3000
- }
3001
- );
3002
- const profileJson = await profileRes.json();
3003
- const profile = profileZ.parse(profileJson);
3004
- const accountsRes = await fetch(
3005
- `https://app.vssps.visualstudio.com/_apis/accounts?memberId=${profile.publicAlias}&api-version=6.0`,
3006
- {
3007
- method: "GET",
3008
- headers: {
3009
- Authorization: `Bearer ${oauthToken}`
3010
- }
3011
- }
3012
- );
3013
- const accountsJson = await accountsRes.json();
3014
- const accounts = accountsZ.parse(accountsJson);
3015
- const orgs = accounts.value.map((account) => account.accountName).filter((value, index, array) => array.indexOf(value) === index);
3016
- return orgs;
3017
- }
3018
- function _getPublicAdoClient({ orgName }) {
3019
- const orgUrl = `https://dev.azure.com/${orgName}`;
3020
- const authHandler = api.getPersonalAccessTokenHandler("");
3021
- authHandler.canHandleAuthentication = () => false;
3022
- authHandler.prepareRequest = (_options) => {
3023
- return;
3560
+ function getUserAndPassword(token) {
3561
+ const [username, password] = token.split(":");
3562
+ const safePasswordAndUsername = z9.object({ username: z9.string(), password: z9.string() }).parse({ username, password });
3563
+ return {
3564
+ username: safePasswordAndUsername.username,
3565
+ password: safePasswordAndUsername.password
3024
3566
  };
3025
- const connection = new api.WebApi(orgUrl, authHandler);
3026
- return connection;
3027
- }
3028
- function getAdoTokenType(token) {
3029
- if (token.includes(".")) {
3030
- return "OAUTH" /* OAUTH */;
3031
- }
3032
- return "PAT" /* PAT */;
3033
3567
  }
3034
- async function getAdoApiClient({
3035
- accessToken,
3036
- tokenOrg,
3037
- orgName
3038
- }) {
3039
- if (!accessToken || tokenOrg && tokenOrg !== orgName) {
3040
- return _getPublicAdoClient({ orgName });
3041
- }
3042
- const orgUrl = `https://dev.azure.com/${orgName}`;
3043
- if (getAdoTokenType(accessToken) === "OAUTH" /* OAUTH */) {
3044
- const connection2 = new api.WebApi(orgUrl, api.getBearerHandler(accessToken));
3045
- return connection2;
3568
+ function createBitbucketSdk(token) {
3569
+ if (!token) {
3570
+ return getBitbucketSdk({ authType: "public" });
3046
3571
  }
3047
- const authHandler = api.getPersonalAccessTokenHandler(accessToken);
3048
- const connection = new api.WebApi(orgUrl, authHandler);
3049
- return connection;
3050
- }
3051
- async function adoValidateParams({
3052
- url,
3053
- accessToken,
3054
- tokenOrg
3055
- }) {
3056
- try {
3057
- if (!url && accessToken && getAdoTokenType(accessToken) === "OAUTH" /* OAUTH */) {
3058
- await _getOrgsForOauthToken({ oauthToken: accessToken });
3059
- return;
3060
- }
3061
- let org = tokenOrg;
3062
- if (url) {
3063
- const { owner } = parseAdoOwnerAndRepo(url);
3064
- org = owner;
3065
- }
3066
- if (!org) {
3067
- throw new InvalidRepoUrlError(`invalid ADO ORG ${org}`);
3068
- }
3069
- const api2 = await getAdoApiClient({
3070
- accessToken,
3071
- tokenOrg,
3072
- orgName: org
3572
+ if (token.includes(":")) {
3573
+ const { password, username } = getUserAndPassword(token);
3574
+ return getBitbucketSdk({
3575
+ authType: "basic",
3576
+ username,
3577
+ password
3073
3578
  });
3074
- await api2.connect();
3075
- } catch (e) {
3076
- const error = e;
3077
- const code = error.code || error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
3078
- const description = error.description || `${e}`;
3079
- if (code === 401 || code === 403 || description.includes("401") || description.includes("403")) {
3080
- throw new InvalidAccessTokenError(`invalid ADO access token`);
3081
- }
3082
- if (code === 404 || description.includes("404") || description.includes("Not Found")) {
3083
- throw new InvalidRepoUrlError(`invalid ADO repo URL ${url}`);
3084
- }
3085
- throw e;
3086
3579
  }
3580
+ return getBitbucketSdk({ authType: "token", token });
3087
3581
  }
3088
- async function getAdoIsUserCollaborator({
3089
- accessToken,
3090
- tokenOrg,
3091
- repoUrl
3092
- }) {
3093
- try {
3094
- const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
3095
- const api2 = await getAdoApiClient({
3096
- accessToken,
3097
- tokenOrg,
3098
- orgName: owner
3099
- });
3100
- const git = await api2.getGitApi();
3101
- const branches = await git.getBranches(repo, projectName);
3102
- if (!branches || branches.length === 0) {
3103
- throw new InvalidRepoUrlError("no branches");
3582
+ var BitbucketSCMLib = class extends SCMLib {
3583
+ constructor(url, accessToken, scmOrg) {
3584
+ super(url, accessToken, scmOrg);
3585
+ __publicField(this, "bitbucketSdk");
3586
+ const bitbucketSdk = createBitbucketSdk(accessToken);
3587
+ this.bitbucketSdk = bitbucketSdk;
3588
+ }
3589
+ getAuthData() {
3590
+ const authType = this.bitbucketSdk.getAuthType();
3591
+ switch (authType) {
3592
+ case "basic": {
3593
+ this._validateToken();
3594
+ const { username, password } = getUserAndPassword(this.accessToken);
3595
+ return { username, password, authType };
3596
+ }
3597
+ case "token": {
3598
+ return { authType, token: z9.string().parse(this.accessToken) };
3599
+ }
3600
+ case "public":
3601
+ return { authType };
3104
3602
  }
3105
- return true;
3106
- } catch (e) {
3107
- return false;
3108
3603
  }
3109
- }
3110
- var adoStatusNumberToEnumMap = {
3111
- 1: "active" /* active */,
3112
- 2: "abandoned" /* abandoned */,
3113
- 3: "completed" /* completed */,
3114
- 4: "all" /* all */
3115
- };
3116
- async function getAdoPullRequestStatus({
3117
- accessToken,
3118
- tokenOrg,
3119
- repoUrl,
3120
- prNumber
3121
- }) {
3122
- const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
3123
- const api2 = await getAdoApiClient({
3124
- accessToken,
3125
- tokenOrg,
3126
- orgName: owner
3127
- });
3128
- const git = await api2.getGitApi();
3129
- const res = await git.getPullRequest(repo, prNumber, projectName);
3130
- if (!res.status || res.status < 1 || res.status > 3) {
3131
- throw new Error("bad pr status for ADO");
3604
+ async createSubmitRequest(params) {
3605
+ this._validateAccessTokenAndUrl();
3606
+ const pullRequestRes = await this.bitbucketSdk.createPullRequest({
3607
+ ...params,
3608
+ repoUrl: this.url
3609
+ });
3610
+ return String(z9.number().parse(pullRequestRes.id));
3132
3611
  }
3133
- return adoStatusNumberToEnumMap[res.status];
3134
- }
3135
- async function getAdoIsRemoteBranch({
3136
- accessToken,
3137
- tokenOrg,
3138
- repoUrl,
3139
- branch
3140
- }) {
3141
- const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
3142
- const api2 = await getAdoApiClient({
3143
- accessToken,
3144
- tokenOrg,
3145
- orgName: owner
3146
- });
3147
- const git = await api2.getGitApi();
3148
- try {
3149
- const branchStatus = await git.getBranch(repo, branch, projectName);
3150
- if (!branchStatus || !branchStatus.commit) {
3151
- throw new InvalidRepoUrlError("no branch status");
3612
+ async validateParams() {
3613
+ return validateBitbucketParams({
3614
+ bitbucketClient: this.bitbucketSdk,
3615
+ url: this.url
3616
+ });
3617
+ }
3618
+ async getRepoList(scmOrg) {
3619
+ this._validateToken();
3620
+ return this.bitbucketSdk.getRepos({
3621
+ workspaceSlug: scmOrg
3622
+ });
3623
+ }
3624
+ async getBranchList() {
3625
+ this._validateAccessTokenAndUrl();
3626
+ return this.bitbucketSdk.getBranchList({
3627
+ repoUrl: this.url
3628
+ });
3629
+ }
3630
+ getScmLibType() {
3631
+ return "BITBUCKET" /* BITBUCKET */;
3632
+ }
3633
+ getAuthHeaders() {
3634
+ const authType = this.bitbucketSdk.getAuthType();
3635
+ switch (authType) {
3636
+ case "public":
3637
+ return {};
3638
+ case "token":
3639
+ return { authorization: `Bearer ${this.accessToken}` };
3640
+ case "basic": {
3641
+ this._validateToken();
3642
+ const { username, password } = getUserAndPassword(this.accessToken);
3643
+ return {
3644
+ authorization: `Basic ${Buffer.from(
3645
+ username + ":" + password
3646
+ ).toString("base64")}`
3647
+ };
3648
+ }
3152
3649
  }
3153
- return branchStatus.name === branch;
3154
- } catch (e) {
3155
- return false;
3156
3650
  }
3157
- }
3158
- async function getAdoRepoList({
3159
- orgName,
3160
- tokenOrg,
3161
- accessToken
3162
- }) {
3163
- let orgs = [];
3164
- if (getAdoTokenType(accessToken) === "OAUTH" /* OAUTH */) {
3165
- orgs = await _getOrgsForOauthToken({ oauthToken: accessToken });
3651
+ async getDownloadUrl(sha) {
3652
+ this._validateUrl();
3653
+ return this.bitbucketSdk.getDownloadUrl({ url: this.url, sha });
3166
3654
  }
3167
- if (orgs.length === 0 && !orgName) {
3168
- throw new Error(`no orgs for ADO`);
3169
- } else if (orgs.length === 0 && orgName) {
3170
- orgs = [orgName];
3655
+ async _getUsernameForAuthUrl() {
3656
+ this._validateAccessTokenAndUrl();
3657
+ const user = await this.bitbucketSdk.getUser();
3658
+ if (!user.username) {
3659
+ throw new Error("no username found");
3660
+ }
3661
+ return user.username;
3171
3662
  }
3172
- const repos = (await Promise.allSettled(
3173
- orgs.map(async (org) => {
3174
- const orgApi = await getAdoApiClient({
3175
- accessToken,
3176
- tokenOrg,
3177
- orgName: org
3663
+ async getIsRemoteBranch(branch) {
3664
+ this._validateAccessTokenAndUrl();
3665
+ try {
3666
+ const res = await this.bitbucketSdk.getBranch({
3667
+ branchName: branch,
3668
+ repoUrl: this.url
3178
3669
  });
3179
- const gitOrg = await orgApi.getGitApi();
3180
- const orgRepos = await gitOrg.getRepositories();
3181
- const repoInfoList = (await Promise.allSettled(
3182
- orgRepos.map(async (repo) => {
3183
- if (!repo.name || !repo.remoteUrl || !repo.defaultBranch) {
3184
- throw new InvalidRepoUrlError("bad repo");
3185
- }
3186
- const branch = await gitOrg.getBranch(
3187
- repo.name,
3188
- repo.defaultBranch.replace(/^refs\/heads\//, ""),
3189
- repo.project?.name
3190
- );
3191
- return {
3192
- repoName: repo.name,
3193
- repoUrl: repo.remoteUrl.replace(
3194
- /^[hH][tT][tT][pP][sS]:\/\/[^/]+@/,
3195
- "https://"
3196
- ),
3197
- repoOwner: org,
3198
- repoIsPublic: repo.project?.visibility === 2,
3199
- //2 is public in the ADO API
3200
- repoLanguages: [],
3201
- repoUpdatedAt: branch.commit?.committer?.date?.toDateString() || repo.project?.lastUpdateTime?.toDateString() || (/* @__PURE__ */ new Date()).toDateString()
3202
- };
3203
- })
3204
- )).reduce((acc, res) => {
3205
- if (res.status === "fulfilled") {
3206
- acc.push(res.value);
3207
- }
3208
- return acc;
3209
- }, []);
3210
- return repoInfoList;
3211
- })
3212
- )).reduce((acc, res) => {
3213
- if (res.status === "fulfilled") {
3214
- return acc.concat(res.value);
3670
+ return res.name === branch;
3671
+ } catch (e) {
3672
+ return false;
3215
3673
  }
3216
- return acc;
3217
- }, []);
3218
- return repos;
3219
- }
3220
- function getAdoPrUrl({
3221
- url,
3222
- prNumber
3223
- }) {
3224
- return `${url}/pullrequest/${prNumber}`;
3225
- }
3226
- function getAdoDownloadUrl({
3227
- repoUrl,
3228
- branch
3229
- }) {
3230
- const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
3231
- const url = new URL(repoUrl);
3232
- const origin = url.origin.toLowerCase().endsWith(".visualstudio.com") ? "https://dev.azure.com" : url.origin.toLowerCase();
3233
- return `${origin}/${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`;
3234
- }
3235
- async function getAdoBranchList({
3236
- accessToken,
3237
- tokenOrg,
3238
- repoUrl
3239
- }) {
3240
- const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
3241
- const api2 = await getAdoApiClient({
3242
- accessToken,
3243
- tokenOrg,
3244
- orgName: owner
3245
- });
3246
- const git = await api2.getGitApi();
3247
- try {
3248
- const res = await git.getBranches(repo, projectName);
3249
- res.sort((a, b) => {
3250
- if (!a.commit?.committer?.date || !b.commit?.committer?.date) {
3251
- return 0;
3252
- }
3253
- return b.commit?.committer?.date.getTime() - a.commit?.committer?.date.getTime();
3674
+ }
3675
+ async getUserHasAccessToRepo() {
3676
+ this._validateAccessTokenAndUrl();
3677
+ return this.bitbucketSdk.getIsUserCollaborator({ repoUrl: this.url });
3678
+ }
3679
+ async getUsername() {
3680
+ this._validateToken();
3681
+ const res = await this.bitbucketSdk.getUser();
3682
+ return z9.string().parse(res.username);
3683
+ }
3684
+ async getSubmitRequestStatus(_scmSubmitRequestId) {
3685
+ this._validateAccessTokenAndUrl();
3686
+ const pullRequestRes = await this.bitbucketSdk.getPullRequest({
3687
+ prNumber: Number(_scmSubmitRequestId),
3688
+ url: this.url
3254
3689
  });
3255
- return res.reduce((acc, branch) => {
3256
- if (!branch.name) {
3257
- return acc;
3258
- }
3259
- acc.push(branch.name);
3260
- return acc;
3261
- }, []);
3262
- } catch (e) {
3690
+ switch (pullRequestRes.state) {
3691
+ case "OPEN":
3692
+ return "open";
3693
+ case "MERGED":
3694
+ return "merged";
3695
+ case "DECLINED":
3696
+ return "closed";
3697
+ default:
3698
+ throw new Error(`unknown state ${pullRequestRes.state} `);
3699
+ }
3700
+ }
3701
+ async getRepoBlameRanges(_ref, _path) {
3263
3702
  return [];
3264
3703
  }
3265
- }
3266
- async function createAdoPullRequest(options) {
3267
- const { owner, repo, projectName } = parseAdoOwnerAndRepo(options.repoUrl);
3268
- const api2 = await getAdoApiClient({
3269
- accessToken: options.accessToken,
3270
- tokenOrg: options.tokenOrg,
3271
- orgName: owner
3272
- });
3273
- const git = await api2.getGitApi();
3274
- const res = await git.createPullRequest(
3275
- {
3276
- sourceRefName: `refs/heads/${options.sourceBranchName}`,
3277
- targetRefName: `refs/heads/${options.targetBranchName}`,
3278
- title: options.title,
3279
- description: options.body
3280
- },
3281
- repo,
3282
- projectName
3283
- );
3284
- return res.pullRequestId;
3285
- }
3286
- async function getAdoRepoDefaultBranch({
3287
- repoUrl,
3288
- tokenOrg,
3289
- accessToken
3290
- }) {
3291
- const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
3292
- const api2 = await getAdoApiClient({
3293
- accessToken,
3294
- tokenOrg,
3295
- orgName: owner
3296
- });
3297
- const git = await api2.getGitApi();
3298
- const branches = await git.getBranches(repo, projectName);
3299
- if (!branches || branches.length === 0) {
3300
- throw new InvalidRepoUrlError("no branches");
3704
+ async getReferenceData(ref) {
3705
+ this._validateUrl();
3706
+ return this.bitbucketSdk.getReferenceData({ url: this.url, ref });
3301
3707
  }
3302
- const res = branches.find((branch) => branch.isBaseVersion);
3303
- if (!res || !res.name) {
3304
- throw new InvalidRepoUrlError("no default branch");
3708
+ async getRepoDefaultBranch() {
3709
+ this._validateUrl();
3710
+ const repoRes = await this.bitbucketSdk.getRepo({ repoUrl: this.url });
3711
+ return z9.string().parse(repoRes.mainbranch?.name);
3305
3712
  }
3306
- return res.name;
3307
- }
3308
- async function getAdoReferenceData({
3309
- ref,
3310
- repoUrl,
3311
- accessToken,
3312
- tokenOrg
3313
- }) {
3314
- const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
3315
- const api2 = await getAdoApiClient({
3316
- accessToken,
3317
- tokenOrg,
3318
- orgName: owner
3319
- });
3320
- if (!projectName) {
3321
- throw new InvalidUrlPatternError("no project name");
3713
+ getPrUrl(prNumber) {
3714
+ this._validateUrl();
3715
+ const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(this.url);
3716
+ return Promise.resolve(
3717
+ `https://bitbucket.org/${workspace}/${repoSlug}/pull-requests/${prNumber}`
3718
+ );
3322
3719
  }
3323
- const git = await api2.getGitApi();
3324
- const results = await Promise.allSettled([
3325
- (async () => {
3326
- const res = await git.getBranch(repo, ref, projectName);
3327
- if (!res.commit || !res.commit.commitId) {
3328
- throw new InvalidRepoUrlError("no commit on branch");
3329
- }
3330
- return {
3331
- sha: res.commit.commitId,
3332
- type: "BRANCH" /* BRANCH */,
3333
- date: res.commit.committer?.date || /* @__PURE__ */ new Date()
3334
- };
3335
- })(),
3336
- (async () => {
3337
- const res = await git.getCommits(
3338
- repo,
3339
- {
3340
- fromCommitId: ref,
3341
- toCommitId: ref,
3342
- $top: 1
3343
- },
3344
- projectName
3345
- );
3346
- const commit = res[0];
3347
- if (!commit || !commit.commitId) {
3348
- throw new Error("no commit");
3720
+ async refreshToken(params) {
3721
+ const getBitbucketTokenResponse = await getBitbucketToken({
3722
+ authType: "refresh_token",
3723
+ ...params
3724
+ });
3725
+ return {
3726
+ accessToken: getBitbucketTokenResponse.access_token,
3727
+ refreshToken: getBitbucketTokenResponse.refresh_token
3728
+ };
3729
+ }
3730
+ };
3731
+
3732
+ // src/features/analysis/scm/bitbucket/bitbucket.ts
3733
+ var { Bitbucket } = bitbucketPkg;
3734
+ var BITBUCKET_HOSTNAME = "bitbucket.org";
3735
+ var TokenExpiredErrorZ = z10.object({
3736
+ status: z10.number(),
3737
+ error: z10.object({
3738
+ type: z10.string(),
3739
+ error: z10.object({
3740
+ message: z10.string()
3741
+ })
3742
+ })
3743
+ });
3744
+ var BITBUCKET_ACCESS_TOKEN_URL = `https://${BITBUCKET_HOSTNAME}/site/oauth2/access_token`;
3745
+ var BitbucketAuthResultZ = z10.object({
3746
+ access_token: z10.string(),
3747
+ token_type: z10.string(),
3748
+ refresh_token: z10.string()
3749
+ });
3750
+ var BitbucketParseResultZ = z10.object({
3751
+ organization: z10.string(),
3752
+ repoName: z10.string(),
3753
+ hostname: z10.literal(BITBUCKET_HOSTNAME)
3754
+ });
3755
+ function parseBitbucketOrganizationAndRepo(bitbucketUrl) {
3756
+ const parsedGitHubUrl = removeTrailingSlash2(bitbucketUrl);
3757
+ const parsingResult = parseScmURL(parsedGitHubUrl, "Bitbucket" /* Bitbucket */);
3758
+ const validatedBitbucketResult = BitbucketParseResultZ.parse(parsingResult);
3759
+ return {
3760
+ workspace: validatedBitbucketResult.organization,
3761
+ repoSlug: validatedBitbucketResult.repoName
3762
+ };
3763
+ }
3764
+ async function getBitbucketToken(params) {
3765
+ const { bitbucketClientId, bitbucketClientSecret, authType } = params;
3766
+ const res = await fetch(BITBUCKET_ACCESS_TOKEN_URL, {
3767
+ method: "POST",
3768
+ headers: {
3769
+ "Content-Type": "application/x-www-form-urlencoded",
3770
+ Authorization: "Basic " + btoa(`${bitbucketClientId}:${bitbucketClientSecret}`)
3771
+ },
3772
+ body: querystring3.stringify(
3773
+ authType === "refresh_token" ? {
3774
+ grant_type: authType,
3775
+ refresh_token: params.refreshToken
3776
+ } : {
3777
+ grant_type: authType,
3778
+ code: params.code
3349
3779
  }
3350
- return {
3351
- sha: commit.commitId,
3352
- type: "COMMIT" /* COMMIT */,
3353
- date: commit.committer?.date || /* @__PURE__ */ new Date()
3354
- };
3355
- })(),
3356
- (async () => {
3357
- const res = await git.getRefs(repo, projectName, `tags/${ref}`);
3358
- if (!res[0] || !res[0].objectId) {
3359
- throw new Error("no tag ref");
3780
+ )
3781
+ });
3782
+ const authResult = await res.json();
3783
+ return BitbucketAuthResultZ.parse(authResult);
3784
+ }
3785
+ function getBitbucketIntance(params) {
3786
+ switch (params.authType) {
3787
+ case "public":
3788
+ return new Bitbucket();
3789
+ case "token":
3790
+ return new Bitbucket({ auth: { token: params.token } });
3791
+ case "basic":
3792
+ return new Bitbucket({
3793
+ auth: {
3794
+ password: params.password,
3795
+ username: params.username
3796
+ }
3797
+ });
3798
+ }
3799
+ }
3800
+ function getBitbucketSdk(params) {
3801
+ const bitbucketClient = getBitbucketIntance(params);
3802
+ return {
3803
+ getAuthType() {
3804
+ return params.authType;
3805
+ },
3806
+ async getRepos(params2) {
3807
+ const repoRes = params2?.workspaceSlug ? await getRepositoriesByWorkspace(bitbucketClient, {
3808
+ workspaceSlug: params2.workspaceSlug
3809
+ }) : await getllUsersrepositories(bitbucketClient);
3810
+ return repoRes.map((repo) => ({
3811
+ repoIsPublic: !repo.is_private,
3812
+ repoName: repo.name || "unknown repo name",
3813
+ repoOwner: repo.owner?.username || "unknown owner",
3814
+ // language can be empty string
3815
+ repoLanguages: repo.language ? [repo.language] : [],
3816
+ repoUpdatedAt: repo.updated_on ? repo.updated_on : (/* @__PURE__ */ new Date()).toISOString(),
3817
+ repoUrl: repo.links?.html?.href || ""
3818
+ }));
3819
+ },
3820
+ async getBranchList(params2) {
3821
+ const { workspace, repoSlug } = parseBitbucketOrganizationAndRepo(
3822
+ params2.repoUrl
3823
+ );
3824
+ const res = await bitbucketClient.refs.listBranches({
3825
+ repo_slug: repoSlug,
3826
+ workspace
3827
+ });
3828
+ if (!res.data.values) {
3829
+ return [];
3360
3830
  }
3361
- let objectId = res[0].objectId;
3362
- try {
3363
- const tag = await git.getAnnotatedTag(projectName, repo, objectId);
3364
- if (tag.taggedObject?.objectId) {
3365
- objectId = tag.taggedObject.objectId;
3831
+ return res.data.values.filter((branch) => !!branch.name).map((branch) => z10.string().parse(branch.name));
3832
+ },
3833
+ async getIsUserCollaborator(params2) {
3834
+ const { repoUrl } = params2;
3835
+ const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(repoUrl);
3836
+ const fullRepoName = `${workspace}/${repoSlug}`;
3837
+ const res = await bitbucketClient.user.listPermissionsForRepos({
3838
+ q: `repository.full_name~"${fullRepoName}"`
3839
+ });
3840
+ return res.data.values?.some(
3841
+ (res2) => res2.repository?.full_name === fullRepoName
3842
+ ) ?? false;
3843
+ },
3844
+ async createPullRequest(params2) {
3845
+ const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
3846
+ params2.repoUrl
3847
+ );
3848
+ const res = await bitbucketClient.pullrequests.create({
3849
+ repo_slug: repoSlug,
3850
+ workspace,
3851
+ _body: {
3852
+ type: "pullrequest",
3853
+ title: params2.title,
3854
+ summary: {
3855
+ raw: params2.body
3856
+ },
3857
+ source: {
3858
+ branch: {
3859
+ name: params2.sourceBranchName
3860
+ }
3861
+ },
3862
+ destination: {
3863
+ branch: {
3864
+ name: params2.targetBranchName
3865
+ }
3866
+ }
3366
3867
  }
3868
+ });
3869
+ return res.data;
3870
+ },
3871
+ async getDownloadlink(params2) {
3872
+ const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
3873
+ params2.repoUrl
3874
+ );
3875
+ const res = await bitbucketClient.downloads.list({
3876
+ repo_slug: repoSlug,
3877
+ workspace
3878
+ });
3879
+ return res.data;
3880
+ },
3881
+ async getBranch(params2) {
3882
+ const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
3883
+ params2.repoUrl
3884
+ );
3885
+ const res = await bitbucketClient.refs.getBranch({
3886
+ name: params2.branchName,
3887
+ repo_slug: repoSlug,
3888
+ workspace
3889
+ });
3890
+ return res.data;
3891
+ },
3892
+ async getRepo(params2) {
3893
+ const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
3894
+ params2.repoUrl
3895
+ );
3896
+ const res = await bitbucketClient.repositories.get({
3897
+ repo_slug: repoSlug,
3898
+ workspace
3899
+ });
3900
+ return res.data;
3901
+ },
3902
+ async getCommit(params2) {
3903
+ const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
3904
+ params2.repoUrl
3905
+ );
3906
+ const res = await bitbucketClient.commits.get({
3907
+ commit: params2.commitSha,
3908
+ repo_slug: repoSlug,
3909
+ workspace
3910
+ });
3911
+ return res.data;
3912
+ },
3913
+ async getUser() {
3914
+ const res = await bitbucketClient.user.get({});
3915
+ return res.data;
3916
+ },
3917
+ async getReferenceData({
3918
+ ref,
3919
+ url
3920
+ }) {
3921
+ try {
3922
+ return await Promise.any([
3923
+ this.getBranchRef({ repoUrl: url, branchName: ref }),
3924
+ this.getTagRef({ repoUrl: url, tagName: ref }),
3925
+ this.getCommitRef({ repoUrl: url, commitSha: ref })
3926
+ ]);
3367
3927
  } catch (e) {
3928
+ console.log("e", e);
3929
+ if (e instanceof AggregateError) {
3930
+ throw new RefNotFoundError(`Invalid reference ${ref} for ${url}`);
3931
+ }
3932
+ throw e;
3368
3933
  }
3369
- const commitRes2 = await git.getCommits(
3370
- repo,
3371
- {
3372
- fromCommitId: objectId,
3373
- toCommitId: objectId,
3374
- $top: 1
3375
- },
3376
- projectName
3934
+ },
3935
+ async getTagRef(params2) {
3936
+ const { tagName, repoUrl } = params2;
3937
+ const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(repoUrl);
3938
+ const tagRes = await bitbucketClient.refs.getTag({
3939
+ repo_slug: repoSlug,
3940
+ workspace,
3941
+ name: tagName
3942
+ });
3943
+ return GetRefererenceResultZ.parse({
3944
+ sha: tagRes.data.target?.hash,
3945
+ type: "TAG" /* TAG */,
3946
+ date: new Date(z10.string().parse(tagRes.data.target?.date))
3947
+ });
3948
+ },
3949
+ async getBranchRef(params2) {
3950
+ const getBranchRes = await this.getBranch(params2);
3951
+ return GetRefererenceResultZ.parse({
3952
+ sha: getBranchRes.target?.hash,
3953
+ type: "BRANCH" /* BRANCH */,
3954
+ date: new Date(z10.string().parse(getBranchRes.target?.date))
3955
+ });
3956
+ },
3957
+ async getCommitRef(params2) {
3958
+ const getCommitRes = await this.getCommit(params2);
3959
+ return GetRefererenceResultZ.parse({
3960
+ sha: getCommitRes.hash,
3961
+ type: "COMMIT" /* COMMIT */,
3962
+ date: new Date(z10.string().parse(getCommitRes.date))
3963
+ });
3964
+ },
3965
+ async getDownloadUrl({ url, sha }) {
3966
+ this.getReferenceData({ ref: sha, url });
3967
+ const repoRes = await this.getRepo({ repoUrl: url });
3968
+ const parsedRepoUrl = z10.string().url().parse(repoRes.links?.html?.href);
3969
+ return `${parsedRepoUrl}/get/${sha}.zip`;
3970
+ },
3971
+ async getPullRequest(params2) {
3972
+ const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
3973
+ params2.url
3377
3974
  );
3378
- const commit = commitRes2[0];
3379
- if (!commit) {
3380
- throw new Error("no commit");
3975
+ const res = await bitbucketClient.pullrequests.get({
3976
+ pull_request_id: params2.prNumber,
3977
+ repo_slug: repoSlug,
3978
+ workspace
3979
+ });
3980
+ return res.data;
3981
+ }
3982
+ };
3983
+ }
3984
+ async function validateBitbucketParams(params) {
3985
+ const { bitbucketClient } = params;
3986
+ const authType = bitbucketClient.getAuthType();
3987
+ console.log("authType", authType, params.url);
3988
+ try {
3989
+ if (authType !== "public") {
3990
+ await bitbucketClient.getUser();
3991
+ }
3992
+ if (params.url) {
3993
+ await bitbucketClient.getRepo({ repoUrl: params.url });
3994
+ }
3995
+ } catch (e) {
3996
+ const safeParseError = TokenExpiredErrorZ.safeParse(e);
3997
+ if (safeParseError.success) {
3998
+ switch (safeParseError.data.status) {
3999
+ case 401:
4000
+ throw new InvalidAccessTokenError(
4001
+ safeParseError.data.error.error.message
4002
+ );
4003
+ case 404:
4004
+ throw new InvalidRepoUrlError(safeParseError.data.error.error.message);
3381
4005
  }
3382
- return {
3383
- sha: objectId,
3384
- type: "TAG" /* TAG */,
3385
- date: commit.committer?.date || /* @__PURE__ */ new Date()
3386
- };
3387
- })()
3388
- ]);
3389
- const [branchRes, commitRes, tagRes] = results;
3390
- if (tagRes.status === "fulfilled") {
3391
- return tagRes.value;
3392
- }
3393
- if (branchRes.status === "fulfilled") {
3394
- return branchRes.value;
3395
- }
3396
- if (commitRes.status === "fulfilled") {
3397
- return commitRes.value;
4006
+ }
4007
+ throw e;
3398
4008
  }
3399
- throw new RefNotFoundError(`ref: ${ref} does not exist`);
3400
4009
  }
3401
- function parseAdoOwnerAndRepo(adoUrl) {
3402
- adoUrl = removeTrailingSlash3(adoUrl);
3403
- const parsingResult = parseScmURL(adoUrl, "Ado" /* Ado */);
3404
- if (!parsingResult || parsingResult.hostname !== "dev.azure.com" && !parsingResult.hostname.endsWith(".visualstudio.com")) {
3405
- throw new InvalidUrlPatternError(`invalid ADO repo URL: ${adoUrl}`);
4010
+ async function getUsersworkspacesSlugs(bitbucketClient) {
4011
+ const res = await bitbucketClient.workspaces.getWorkspaces({});
4012
+ return res.data.values?.map((v) => z10.string().parse(v.slug));
4013
+ }
4014
+ async function getllUsersrepositories(bitbucketClient) {
4015
+ const userWorspacesSlugs = await getUsersworkspacesSlugs(bitbucketClient);
4016
+ if (!userWorspacesSlugs) {
4017
+ return [];
3406
4018
  }
3407
- const { organization, repoName, projectName, projectPath, pathElements } = parsingResult;
3408
- return {
3409
- owner: organization,
3410
- repo: repoName,
3411
- projectName,
3412
- projectPath,
3413
- pathElements
3414
- };
4019
+ const allWorkspaceRepos = [];
4020
+ for (const workspaceSlug of userWorspacesSlugs) {
4021
+ const repos = await bitbucketClient.repositories.list({
4022
+ workspace: workspaceSlug
4023
+ });
4024
+ if (!repos.data.values) {
4025
+ continue;
4026
+ }
4027
+ allWorkspaceRepos.push(...repos.data.values);
4028
+ }
4029
+ return allWorkspaceRepos;
3415
4030
  }
3416
- async function getAdoBlameRanges() {
3417
- return [];
4031
+ async function getRepositoriesByWorkspace(bitbucketClient, { workspaceSlug }) {
4032
+ const res = await bitbucketClient.repositories.list({
4033
+ workspace: workspaceSlug
4034
+ });
4035
+ return res.data.values ?? [];
3418
4036
  }
3419
- var AdoAuthResultZ = z9.object({
3420
- access_token: z9.string().min(1),
3421
- token_type: z9.string().min(1),
3422
- refresh_token: z9.string().min(1)
3423
- });
3424
4037
 
3425
4038
  // src/features/analysis/scm/constants.ts
3426
4039
  var MOBB_ICON_IMG = "https://app.mobb.ai/gh-action/Logo_Rounded_Icon.svg";
3427
4040
  var COMMIT_FIX_SVG = `https://app.mobb.ai/gh-action/commit-button.svg`;
3428
4041
 
3429
- // src/features/analysis/scm/utils/get_issue_type.ts
3430
- var getIssueType = (issueType) => {
3431
- switch (issueType) {
3432
- case "SQL_Injection" /* SqlInjection */:
3433
- return "SQL Injection";
3434
- case "CMDi_relative_path_command" /* CmDiRelativePathCommand */:
3435
- return "Relative Path Command Injection";
3436
- case "CMDi" /* CmDi */:
3437
- return "Command Injection";
3438
- case "XXE" /* Xxe */:
3439
- return "XXE";
3440
- case "XSS" /* Xss */:
3441
- return "XSS";
3442
- case "PT" /* Pt */:
3443
- return "Path Traversal";
3444
- case "ZIP_SLIP" /* ZipSlip */:
3445
- return "Zip Slip";
3446
- case "INSECURE_RANDOMNESS" /* InsecureRandomness */:
3447
- return "Insecure Randomness";
3448
- case "SSRF" /* Ssrf */:
3449
- return "Server Side Request Forgery";
3450
- case "TYPE_CONFUSION" /* TypeConfusion */:
3451
- return "Type Confusion";
3452
- case "REGEX_INJECTION" /* RegexInjection */:
3453
- return "Regular Expression Injection";
3454
- case "INCOMPLETE_URL_SANITIZATION" /* IncompleteUrlSanitization */:
3455
- return "Incomplete URL Sanitization";
3456
- case "LOG_FORGING" /* LogForging */:
3457
- return "Log Forging";
3458
- case "LOCALE_DEPENDENT_COMPARISON" /* LocaleDependentComparison */:
3459
- return "Locale Dependent Comparison";
3460
- case "MISSING_CHECK_AGAINST_NULL" /* MissingCheckAgainstNull */:
3461
- return "Missing Check against Null";
3462
- case "PASSWORD_IN_COMMENT" /* PasswordInComment */:
3463
- return "Password in Comment";
3464
- case "OVERLY_BROAD_CATCH" /* OverlyBroadCatch */:
3465
- return "Poor Error Handling: Overly Broad Catch";
3466
- case "USE_OF_SYSTEM_OUTPUT_STREAM" /* UseOfSystemOutputStream */:
3467
- return "Use of System.out/System.err";
3468
- case "DANGEROUS_FUNCTION_OVERFLOW" /* DangerousFunctionOverflow */:
3469
- return "Use of dangerous function";
3470
- case "DOS_STRING_BUILDER" /* DosStringBuilder */:
3471
- return "Denial of Service: StringBuilder";
3472
- case "OPEN_REDIRECT" /* OpenRedirect */:
3473
- return "Open Redirect";
3474
- case "WEAK_XML_SCHEMA_UNBOUNDED_OCCURRENCES" /* WeakXmlSchemaUnboundedOccurrences */:
3475
- return "Weak XML Schema: Unbounded Occurrences";
3476
- case "SYSTEM_INFORMATION_LEAK" /* SystemInformationLeak */:
3477
- return "System Information Leak";
3478
- case "HTTP_RESPONSE_SPLITTING" /* HttpResponseSplitting */:
3479
- return "HTTP response splitting";
3480
- case "HTTP_ONLY_COOKIE" /* HttpOnlyCookie */:
3481
- return "Cookie is not HttpOnly";
3482
- case "INSECURE_COOKIE" /* InsecureCookie */:
3483
- return "Insecure Cookie";
3484
- case "TRUST_BOUNDARY_VIOLATION" /* TrustBoundaryViolation */:
3485
- return "Trust Boundary Violation";
3486
- case "MISSING_EQUALS_OR_HASHCODE" /* MissingEqualsOrHashcode */:
3487
- return "Missing equals or hashcode method";
3488
- default: {
3489
- return issueType ? issueType.replaceAll("_", " ") : "Other";
3490
- }
3491
- }
3492
- };
3493
-
3494
- // src/features/analysis/scm/utils/index.ts
3495
- function getFixUrlWithRedirect(params) {
3496
- const {
3497
- fixId,
3498
- projectId,
3499
- organizationId,
3500
- analysisId,
3501
- redirectUrl,
3502
- appBaseUrl,
3503
- commentId
3504
- } = params;
3505
- const searchParams = new URLSearchParams();
3506
- searchParams.append("commit_redirect_url", redirectUrl);
3507
- searchParams.append("comment_id", commentId.toString());
3508
- return `${getFixUrl({
3509
- appBaseUrl,
3510
- fixId,
3511
- projectId,
3512
- organizationId,
3513
- analysisId
3514
- })}?${searchParams.toString()}`;
3515
- }
3516
- function getFixUrl({
3517
- appBaseUrl,
3518
- fixId,
3519
- projectId,
3520
- organizationId,
3521
- analysisId
3522
- }) {
3523
- return `${appBaseUrl}/organization/${organizationId}/project/${projectId}/report/${analysisId}/fix/${fixId}`;
3524
- }
3525
- function getCommitUrl(params) {
3526
- const {
3527
- fixId,
3528
- projectId,
3529
- organizationId,
3530
- analysisId,
3531
- redirectUrl,
3532
- appBaseUrl,
3533
- commentId
3534
- } = params;
3535
- const searchParams = new URLSearchParams();
3536
- searchParams.append("redirect_url", redirectUrl);
3537
- searchParams.append("comment_id", commentId.toString());
3538
- return `${getFixUrl({
3539
- appBaseUrl,
3540
- fixId,
3541
- projectId,
3542
- organizationId,
3543
- analysisId
3544
- })}/commit?${searchParams.toString()}`;
3545
- }
3546
-
3547
4042
  // src/features/analysis/utils/by_key.ts
3548
4043
  function keyBy(array, keyBy2) {
3549
4044
  return array.reduce((acc, item) => {
@@ -3613,6 +4108,16 @@ async function sendReport({
3613
4108
  }
3614
4109
  }
3615
4110
 
4111
+ // src/features/analysis/utils/index.ts
4112
+ function getFromArraySafe(array) {
4113
+ return array.reduce((acc, nullableItem) => {
4114
+ if (nullableItem) {
4115
+ acc.push(nullableItem);
4116
+ }
4117
+ return acc;
4118
+ }, []);
4119
+ }
4120
+
3616
4121
  // src/features/analysis/handle_finished_analysis.ts
3617
4122
  var debug5 = Debug5("mobbdev:handle-finished-analysis");
3618
4123
  var contactUsMarkdown = `For specific requests [contact us](https://mobb.ai/contact) and we'll do the most to answer your need quickly.`;
@@ -3641,7 +4146,7 @@ async function getRelevantVulenrabilitiesFromDiff(params) {
3641
4146
  });
3642
4147
  const lineAddedRanges = calculateRanges(fileNumbers);
3643
4148
  const fileFilter = {
3644
- path: z10.string().parse(file.to),
4149
+ path: z11.string().parse(file.to),
3645
4150
  ranges: lineAddedRanges.map(([startLine, endLine]) => ({
3646
4151
  endLine,
3647
4152
  startLine
@@ -4439,9 +4944,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
4439
4944
  apiKey: apiKey || config2.get("apiToken")
4440
4945
  });
4441
4946
  await handleMobbLogin();
4442
- const { projectId, organizationId } = await gqlClient.getOrgAndProjectId(
4443
- mobbProjectName
4444
- );
4947
+ const { projectId, organizationId } = await gqlClient.getOrgAndProjectId(mobbProjectName);
4445
4948
  const {
4446
4949
  uploadS3BucketInfo: { repoUploadInfo, reportUploadInfo }
4447
4950
  } = await gqlClient.uploadS3BucketInfo();
@@ -4456,12 +4959,10 @@ async function _scan(params, { skipPrompts = false } = {}) {
4456
4959
  throw new Error("repo is required in case srcPath is not provided");
4457
4960
  }
4458
4961
  const userInfo = await gqlClient.getUserInfo();
4459
- const scmConfigs = [];
4460
- for (const scmConfig of userInfo?.scmConfigs || []) {
4461
- if (scmConfig?.__typename === "ScmConfig") {
4462
- scmConfigs.push(scmConfig);
4463
- }
4962
+ if (!userInfo) {
4963
+ throw new Error("userInfo is null");
4464
4964
  }
4965
+ const scmConfigs = getFromArraySafe(userInfo.scmConfigs);
4465
4966
  const tokenInfo = getScmConfig({
4466
4967
  url: repo,
4467
4968
  scmConfigs,
@@ -4506,6 +5007,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
4506
5007
  });
4507
5008
  const reference = ref ?? await scm.getRepoDefaultBranch();
4508
5009
  const { sha } = await scm.getReferenceData(reference);
5010
+ const downloadUrl = await scm.getDownloadUrl(sha);
4509
5011
  debug10("org id %s", organizationId);
4510
5012
  debug10("project id %s", projectId);
4511
5013
  debug10("default branch %s", reference);
@@ -4514,7 +5016,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
4514
5016
  dirname,
4515
5017
  ci,
4516
5018
  authHeaders: scm.getAuthHeaders(),
4517
- downloadUrl: scm.getDownloadUrl(sha)
5019
+ downloadUrl
4518
5020
  });
4519
5021
  if (command === "scan") {
4520
5022
  reportPath = await getReport(SupportedScannersZ.parse(scanner));
@@ -4541,7 +5043,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
4541
5043
  spinner: mobbSpinner,
4542
5044
  submitVulnerabilityReportVariables: {
4543
5045
  fixReportId: reportUploadInfo.fixReportId,
4544
- repoUrl: z11.string().parse(repo),
5046
+ repoUrl: z12.string().parse(repo),
4545
5047
  reference,
4546
5048
  projectId,
4547
5049
  vulnerabilityReportFileName: "report.json",
@@ -4563,8 +5065,8 @@ async function _scan(params, { skipPrompts = false } = {}) {
4563
5065
  analysisId,
4564
5066
  gqlClient,
4565
5067
  scm,
4566
- githubActionToken: z11.string().parse(githubActionToken),
4567
- scanner: z11.nativeEnum(SCANNERS).parse(scanner)
5068
+ githubActionToken: z12.string().parse(githubActionToken),
5069
+ scanner: z12.nativeEnum(SCANNERS).parse(scanner)
4568
5070
  }),
4569
5071
  callbackStates: ["Finished" /* Finished */]
4570
5072
  });
@@ -4693,12 +5195,10 @@ async function _scan(params, { skipPrompts = false } = {}) {
4693
5195
  await open2(scmAuthUrl2);
4694
5196
  for (let i = 0; i < LOGIN_MAX_WAIT / LOGIN_CHECK_DELAY; i++) {
4695
5197
  const userInfo2 = await gqlClient.getUserInfo();
4696
- const scmConfigs2 = [];
4697
- for (const scmConfig of userInfo2?.scmConfigs || []) {
4698
- if (scmConfig?.__typename === "ScmConfig") {
4699
- scmConfigs2.push(scmConfig);
4700
- }
5198
+ if (!userInfo2) {
5199
+ throw new CliError2("User info not found");
4701
5200
  }
5201
+ const scmConfigs2 = getFromArraySafe(userInfo2.scmConfigs);
4702
5202
  const tokenInfo2 = getScmConfig({
4703
5203
  url: repoUrl,
4704
5204
  scmConfigs: scmConfigs2,
@@ -4974,21 +5474,22 @@ var commitHashOption = {
4974
5474
  };
4975
5475
  var scmTypeOption = {
4976
5476
  demandOption: true,
4977
- describe: chalk5.bold("SCM type (GitHub, GitLab, Ado)"),
5477
+ describe: chalk5.bold("SCM type (GitHub, GitLab, Ado, Bitbucket)"),
4978
5478
  type: "string"
4979
5479
  };
4980
5480
  var urlOption = {
4981
5481
  describe: chalk5.bold(
4982
- "URL of the repository (used in GitHub, GitLab, Azure DevOps)"
5482
+ "URL of the repository (used in GitHub, GitLab, Azure DevOps, Bitbucket)"
4983
5483
  ),
4984
- type: "string"
5484
+ type: "string",
5485
+ demandOption: true
4985
5486
  };
4986
5487
  var scmOrgOption = {
4987
5488
  describe: chalk5.bold("Organization name in SCM (used in Azure DevOps)"),
4988
5489
  type: "string"
4989
5490
  };
4990
5491
  var scmUsernameOption = {
4991
- describe: chalk5.bold("Username in SCM (used in GitHub)"),
5492
+ describe: chalk5.bold("Username in SCM (used in GitHub, Bitbucket)"),
4992
5493
  type: "string"
4993
5494
  };
4994
5495
  var scmRefreshTokenOption = {
@@ -4997,13 +5498,14 @@ var scmRefreshTokenOption = {
4997
5498
  };
4998
5499
  var scmTokenOption = {
4999
5500
  describe: chalk5.bold("SCM API token"),
5000
- type: "string"
5501
+ type: "string",
5502
+ demandOption: true
5001
5503
  };
5002
5504
 
5003
5505
  // src/args/validation.ts
5004
5506
  import chalk6 from "chalk";
5005
5507
  import path8 from "path";
5006
- import { z as z12 } from "zod";
5508
+ import { z as z13 } from "zod";
5007
5509
  function throwRepoUrlErrorMessage({
5008
5510
  error,
5009
5511
  repoUrl,
@@ -5020,7 +5522,7 @@ Example:
5020
5522
  )}`;
5021
5523
  throw new CliError(formattedErrorMessage);
5022
5524
  }
5023
- var UrlZ = z12.string({
5525
+ var UrlZ = z13.string({
5024
5526
  invalid_type_error: "is not a valid GitHub / GitLab / ADO URL"
5025
5527
  }).refine((data) => !!sanityRepoURL(data), {
5026
5528
  message: "is not a valid GitHub / GitLab / ADO URL"
@@ -5168,6 +5670,7 @@ async function scanHandler(args) {
5168
5670
  }
5169
5671
 
5170
5672
  // src/args/commands/token.ts
5673
+ import { z as z14 } from "zod";
5171
5674
  function addScmTokenBuilder(args) {
5172
5675
  return args.option("scm-type", scmTypeOption).option("url", urlOption).option("token", scmTokenOption).option("organization", scmOrgOption).option("username", scmUsernameOption).option("refresh-token", scmRefreshTokenOption).option("api-key", apiKeyOption).example(
5173
5676
  "$0 add-scm-token --scm-type Ado --url https://dev.azure.com/adoorg/test/_git/repo --token abcdef0123456 --organization myOrg",
@@ -5175,22 +5678,36 @@ function addScmTokenBuilder(args) {
5175
5678
  ).help().demandOption(["url", "token"]);
5176
5679
  }
5177
5680
  function validateAddScmTokenOptions(argv) {
5178
- if (!argv.url) {
5179
- throw new CliError(errorMessages.missingUrl);
5180
- }
5181
- if (!argv.token) {
5182
- throw new CliError(errorMessages.missingToken);
5183
- }
5184
- if ("GitHub" /* GitHub */ !== argv.scmType && "Ado" /* Ado */ !== argv.scmType && "GitLab" /* GitLab */ !== argv.scmType) {
5681
+ if (!z14.nativeEnum(ScmType).safeParse(argv.scmType).success) {
5185
5682
  throw new CliError(
5186
- "\nError: --scm-type must reference a valid SCM type (GitHub, GitLab, Ado)"
5683
+ "\nError: --scm-type must reference a valid SCM type (GitHub, GitLab, Ado, Bitbutcket)"
5187
5684
  );
5188
5685
  }
5686
+ Object.values(scmValidationMap).forEach((validate) => validate(argv));
5687
+ }
5688
+ var scmValidationMap = {
5689
+ ["GitHub" /* GitHub */]: validateGithub,
5690
+ ["GitLab" /* GitLab */]: () => {
5691
+ return;
5692
+ },
5693
+ ["Ado" /* Ado */]: validateAdo,
5694
+ ["Bitbucket" /* Bitbucket */]: validateBitbucket
5695
+ };
5696
+ function validateBitbucket(argv) {
5697
+ const urlObj = new URL(argv.url);
5698
+ if (urlObj.hostname.toLowerCase() === scmCloudHostname.Bitbucket && !argv.username) {
5699
+ throw new CliError("\nError: --username flag is required for Bitbucket");
5700
+ }
5701
+ }
5702
+ function validateGithub(argv) {
5189
5703
  const urlObj = new URL(argv.url);
5190
- if (urlObj.hostname.toLowerCase() === "github.com" && !argv.username) {
5704
+ if (urlObj.hostname.toLowerCase() === scmCloudHostname.GitHub && !argv.username) {
5191
5705
  throw new CliError("\nError: --username flag is required for GitHub");
5192
5706
  }
5193
- if ((urlObj.hostname.toLowerCase() === "dev.azure.com" || urlObj.hostname.toLowerCase().endsWith(".visualstudio.com")) && !argv.organization) {
5707
+ }
5708
+ function validateAdo(argv) {
5709
+ const urlObj = new URL(argv.url);
5710
+ if ((urlObj.hostname.toLowerCase() === scmCloudHostname.Ado || urlObj.hostname.toLowerCase().endsWith(".visualstudio.com")) && !argv.organization) {
5194
5711
  throw new CliError(
5195
5712
  "\nError: --organization flag is required for Azure DevOps"
5196
5713
  );