mobbdev 0.0.143 → 0.0.145
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +1114 -1074
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -528,16 +528,11 @@ import fetch4 from "node-fetch";
|
|
|
528
528
|
import open2 from "open";
|
|
529
529
|
import semver from "semver";
|
|
530
530
|
import tmp2 from "tmp";
|
|
531
|
-
import { z as
|
|
531
|
+
import { z as z12 } from "zod";
|
|
532
532
|
|
|
533
533
|
// src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
|
|
534
534
|
import Debug4 from "debug";
|
|
535
535
|
|
|
536
|
-
// src/features/analysis/scm/ado.ts
|
|
537
|
-
import querystring from "node:querystring";
|
|
538
|
-
import * as api from "azure-devops-node-api";
|
|
539
|
-
import { z as z2 } from "zod";
|
|
540
|
-
|
|
541
536
|
// src/features/analysis/scm/types.ts
|
|
542
537
|
var ReferenceType = /* @__PURE__ */ ((ReferenceType2) => {
|
|
543
538
|
ReferenceType2["BRANCH"] = "BRANCH";
|
|
@@ -566,6 +561,35 @@ var ScmType = /* @__PURE__ */ ((ScmType2) => {
|
|
|
566
561
|
return ScmType2;
|
|
567
562
|
})(ScmType || {});
|
|
568
563
|
|
|
564
|
+
// src/features/analysis/scm/ado/constants.ts
|
|
565
|
+
var DEFUALT_ADO_ORIGIN = scmCloudUrl.Ado;
|
|
566
|
+
|
|
567
|
+
// src/features/analysis/scm/ado/utils.ts
|
|
568
|
+
import querystring3 from "node:querystring";
|
|
569
|
+
import * as api from "azure-devops-node-api";
|
|
570
|
+
import { z as z9 } from "zod";
|
|
571
|
+
|
|
572
|
+
// src/features/analysis/scm/env.ts
|
|
573
|
+
import { z as z2 } from "zod";
|
|
574
|
+
var EnvVariablesZod = z2.object({
|
|
575
|
+
GITLAB_API_TOKEN: z2.string().optional(),
|
|
576
|
+
BROKERED_HOSTS: z2.string().toLowerCase().transform(
|
|
577
|
+
(x) => x.split(",").map((url) => url.trim(), []).filter(Boolean)
|
|
578
|
+
).default(""),
|
|
579
|
+
GITHUB_API_TOKEN: z2.string().optional(),
|
|
580
|
+
GIT_PROXY_HOST: z2.string().default("http://tinyproxy:8888")
|
|
581
|
+
});
|
|
582
|
+
var { GITLAB_API_TOKEN, BROKERED_HOSTS, GITHUB_API_TOKEN, GIT_PROXY_HOST } = EnvVariablesZod.parse(process.env);
|
|
583
|
+
|
|
584
|
+
// src/features/analysis/scm/scm.ts
|
|
585
|
+
import { z as z7 } from "zod";
|
|
586
|
+
|
|
587
|
+
// src/features/analysis/scm/bitbucket/bitbucket.ts
|
|
588
|
+
import querystring from "node:querystring";
|
|
589
|
+
import bitbucketPkg from "bitbucket";
|
|
590
|
+
import * as bitbucketPkgNode from "bitbucket";
|
|
591
|
+
import { z as z3 } from "zod";
|
|
592
|
+
|
|
569
593
|
// src/features/analysis/scm/urlParser.ts
|
|
570
594
|
function detectAdoUrl(args) {
|
|
571
595
|
const { pathname, hostname, scmType } = args;
|
|
@@ -710,509 +734,519 @@ var sanityRepoURL = (scmURL) => {
|
|
|
710
734
|
}
|
|
711
735
|
};
|
|
712
736
|
|
|
713
|
-
// src/features/analysis/scm/
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
"
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
737
|
+
// src/features/analysis/scm/utils/get_issue_type.ts
|
|
738
|
+
var getIssueType = (issueType) => {
|
|
739
|
+
switch (issueType) {
|
|
740
|
+
case "SQL_Injection" /* SqlInjection */:
|
|
741
|
+
return "SQL Injection";
|
|
742
|
+
case "CMDi_relative_path_command" /* CmDiRelativePathCommand */:
|
|
743
|
+
return "Relative Path Command Injection";
|
|
744
|
+
case "CMDi" /* CmDi */:
|
|
745
|
+
return "Command Injection";
|
|
746
|
+
case "XXE" /* Xxe */:
|
|
747
|
+
return "XXE";
|
|
748
|
+
case "XSS" /* Xss */:
|
|
749
|
+
return "XSS";
|
|
750
|
+
case "PT" /* Pt */:
|
|
751
|
+
return "Path Traversal";
|
|
752
|
+
case "ZIP_SLIP" /* ZipSlip */:
|
|
753
|
+
return "Zip Slip";
|
|
754
|
+
case "INSECURE_RANDOMNESS" /* InsecureRandomness */:
|
|
755
|
+
return "Insecure Randomness";
|
|
756
|
+
case "SSRF" /* Ssrf */:
|
|
757
|
+
return "Server Side Request Forgery";
|
|
758
|
+
case "TYPE_CONFUSION" /* TypeConfusion */:
|
|
759
|
+
return "Type Confusion";
|
|
760
|
+
case "REGEX_INJECTION" /* RegexInjection */:
|
|
761
|
+
return "Regular Expression Injection";
|
|
762
|
+
case "INCOMPLETE_URL_SANITIZATION" /* IncompleteUrlSanitization */:
|
|
763
|
+
return "Incomplete URL Sanitization";
|
|
764
|
+
case "LOCALE_DEPENDENT_COMPARISON" /* LocaleDependentComparison */:
|
|
765
|
+
return "Locale Dependent Comparison";
|
|
766
|
+
case "LOG_FORGING" /* LogForging */:
|
|
767
|
+
return "Log Forging";
|
|
768
|
+
case "MISSING_CHECK_AGAINST_NULL" /* MissingCheckAgainstNull */:
|
|
769
|
+
return "Missing Check against Null";
|
|
770
|
+
case "PASSWORD_IN_COMMENT" /* PasswordInComment */:
|
|
771
|
+
return "Password in Comment";
|
|
772
|
+
case "OVERLY_BROAD_CATCH" /* OverlyBroadCatch */:
|
|
773
|
+
return "Poor Error Handling: Overly Broad Catch";
|
|
774
|
+
case "USE_OF_SYSTEM_OUTPUT_STREAM" /* UseOfSystemOutputStream */:
|
|
775
|
+
return "Use of System.out/System.err";
|
|
776
|
+
case "DANGEROUS_FUNCTION_OVERFLOW" /* DangerousFunctionOverflow */:
|
|
777
|
+
return "Use of dangerous function";
|
|
778
|
+
case "DOS_STRING_BUILDER" /* DosStringBuilder */:
|
|
779
|
+
return "Denial of Service: StringBuilder";
|
|
780
|
+
case "OPEN_REDIRECT" /* OpenRedirect */:
|
|
781
|
+
return "Open Redirect";
|
|
782
|
+
case "WEAK_XML_SCHEMA_UNBOUNDED_OCCURRENCES" /* WeakXmlSchemaUnboundedOccurrences */:
|
|
783
|
+
return "Weak XML Schema: Unbounded Occurrences";
|
|
784
|
+
case "SYSTEM_INFORMATION_LEAK" /* SystemInformationLeak */:
|
|
785
|
+
return "System Information Leak";
|
|
786
|
+
case "SYSTEM_INFORMATION_LEAK_EXTERNAL" /* SystemInformationLeakExternal */:
|
|
787
|
+
return "External System Information Leak";
|
|
788
|
+
case "HTTP_RESPONSE_SPLITTING" /* HttpResponseSplitting */:
|
|
789
|
+
return "HTTP response splitting";
|
|
790
|
+
case "HTTP_ONLY_COOKIE" /* HttpOnlyCookie */:
|
|
791
|
+
return "Cookie is not HttpOnly";
|
|
792
|
+
case "INSECURE_COOKIE" /* InsecureCookie */:
|
|
793
|
+
return "Insecure Cookie";
|
|
794
|
+
case "TRUST_BOUNDARY_VIOLATION" /* TrustBoundaryViolation */:
|
|
795
|
+
return "Trust Boundary Violation";
|
|
796
|
+
case "NULL_DEREFERENCE" /* NullDereference */:
|
|
797
|
+
return "Null Dereference";
|
|
798
|
+
case "UNSAFE_DESERIALIZATION" /* UnsafeDeserialization */:
|
|
799
|
+
return "Unsafe deserialization";
|
|
800
|
+
case "INSECURE_BINDER_CONFIGURATION" /* InsecureBinderConfiguration */:
|
|
801
|
+
return "Insecure Binder Configuration";
|
|
802
|
+
case "UNSAFE_TARGET_BLANK" /* UnsafeTargetBlank */:
|
|
803
|
+
return "Unsafe use of target blank";
|
|
804
|
+
case "IFRAME_WITHOUT_SANDBOX" /* IframeWithoutSandbox */:
|
|
805
|
+
return "Client use of iframe without sandbox";
|
|
806
|
+
case "JQUERY_DEPRECATED_SYMBOLS" /* JqueryDeprecatedSymbols */:
|
|
807
|
+
return "jQuery deprecated symbols";
|
|
808
|
+
case "MISSING_ANTIFORGERY_VALIDATION" /* MissingAntiforgeryValidation */:
|
|
809
|
+
return "Missing Anti-Forgery Validation";
|
|
810
|
+
case "GRAPHQL_DEPTH_LIMIT" /* GraphqlDepthLimit */:
|
|
811
|
+
return "GraphQL Depth Limit";
|
|
812
|
+
case "UNCHECKED_LOOP_CONDITION" /* UncheckedLoopCondition */:
|
|
813
|
+
return "Unchecked Loop Condition";
|
|
814
|
+
case "IMPROPER_RESOURCE_SHUTDOWN_OR_RELEASE" /* ImproperResourceShutdownOrRelease */:
|
|
815
|
+
return "Improper Resource Shutdown or Release";
|
|
816
|
+
case "IMPROPER_EXCEPTION_HANDLING" /* ImproperExceptionHandling */:
|
|
817
|
+
return "Improper Exception Handling";
|
|
818
|
+
case "DEFAULT_RIGHTS_IN_OBJ_DEFINITION" /* DefaultRightsInObjDefinition */:
|
|
819
|
+
return "Default Definer Rights in Package or Object Definition";
|
|
820
|
+
case "HTML_COMMENT_IN_JSP" /* HtmlCommentInJsp */:
|
|
821
|
+
return "HTML Comment in JSP";
|
|
822
|
+
case "ERROR_CONDTION_WITHOUT_ACTION" /* ErrorCondtionWithoutAction */:
|
|
823
|
+
return "Error Condition Without Action";
|
|
824
|
+
case "DEPRECATED_FUNCTION" /* DeprecatedFunction */:
|
|
825
|
+
return "Deprecated Function";
|
|
826
|
+
case "HARDCODED_SECRETS" /* HardcodedSecrets */:
|
|
827
|
+
return "Hardcoded Secrets";
|
|
828
|
+
case "PROTOTYPE_POLLUTION" /* PrototypePollution */:
|
|
829
|
+
return "Prototype Pollution";
|
|
830
|
+
case "RACE_CONDITION_FORMAT_FLAW" /* RaceConditionFormatFlaw */:
|
|
831
|
+
return "Race Condition Format Flaw";
|
|
832
|
+
case "NON_FINAL_PUBLIC_STATIC_FIELD" /* NonFinalPublicStaticField */:
|
|
833
|
+
return "Non-final Public Static Field";
|
|
834
|
+
case "MISSING_HSTS_HEADER" /* MissingHstsHeader */:
|
|
835
|
+
return "Missing HSTS Header";
|
|
836
|
+
case "DEAD_CODE_UNUSED_FIELD" /* DeadCodeUnusedField */:
|
|
837
|
+
return "Dead Code: Unused Field";
|
|
838
|
+
case "HEADER_MANIPULATION" /* HeaderManipulation */:
|
|
839
|
+
return "Header Manipulation";
|
|
840
|
+
case "MISSING_EQUALS_OR_HASHCODE" /* MissingEqualsOrHashcode */:
|
|
841
|
+
return "Missing equals or hashcode method";
|
|
842
|
+
case "WCF_MISCONFIGURATION_INSUFFICIENT_LOGGING" /* WcfMisconfigurationInsufficientLogging */:
|
|
843
|
+
return "WCF Misconfiguration: Insufficient Logging";
|
|
844
|
+
case "WCF_MISCONFIGURATION_THROTTLING_NOT_ENABLED" /* WcfMisconfigurationThrottlingNotEnabled */:
|
|
845
|
+
return "WCF Misconfiguration: Throttling Not Enabled";
|
|
846
|
+
case "USELESS_REGEXP_CHAR_ESCAPE" /* UselessRegexpCharEscape */:
|
|
847
|
+
return "Useless regular-expression character escape";
|
|
848
|
+
case "INCOMPLETE_HOSTNAME_REGEX" /* IncompleteHostnameRegex */:
|
|
849
|
+
return "Incomplete Hostname Regex";
|
|
850
|
+
case "OVERLY_LARGE_RANGE" /* OverlyLargeRange */:
|
|
851
|
+
return "Regex: Overly Large Range";
|
|
852
|
+
case "INSUFFICIENT_LOGGING" /* InsufficientLogging */:
|
|
853
|
+
return "Insufficient Logging of Sensitive Operations";
|
|
854
|
+
case "PRIVACY_VIOLATION" /* PrivacyViolation */:
|
|
855
|
+
return "Privacy Violation";
|
|
856
|
+
case "INCOMPLETE_URL_SCHEME_CHECK" /* IncompleteUrlSchemeCheck */:
|
|
857
|
+
return "Incomplete URL Scheme Check";
|
|
858
|
+
case "VALUE_NEVER_READ" /* ValueNeverRead */:
|
|
859
|
+
return "Value Never Read";
|
|
860
|
+
case "VALUE_SHADOWING" /* ValueShadowing */:
|
|
861
|
+
return "Value Shadowing";
|
|
862
|
+
default: {
|
|
863
|
+
return issueType ? issueType.replaceAll("_", " ") : "Other";
|
|
755
864
|
}
|
|
756
|
-
);
|
|
757
|
-
const accountsJson = await accountsRes.json();
|
|
758
|
-
const accounts = accountsZ.parse(accountsJson);
|
|
759
|
-
const orgs = accounts.value.map((account) => account.accountName).filter((value, index, array) => array.indexOf(value) === index);
|
|
760
|
-
return orgs;
|
|
761
|
-
}
|
|
762
|
-
function _getPublicAdoClient({ orgName }) {
|
|
763
|
-
const orgUrl = `https://dev.azure.com/${orgName}`;
|
|
764
|
-
const authHandler = api.getPersonalAccessTokenHandler("");
|
|
765
|
-
authHandler.canHandleAuthentication = () => false;
|
|
766
|
-
authHandler.prepareRequest = (_options) => {
|
|
767
|
-
return;
|
|
768
|
-
};
|
|
769
|
-
const connection = new api.WebApi(orgUrl, authHandler);
|
|
770
|
-
return connection;
|
|
771
|
-
}
|
|
772
|
-
function getAdoTokenType(token) {
|
|
773
|
-
if (token.includes(".")) {
|
|
774
|
-
return "OAUTH" /* OAUTH */;
|
|
775
865
|
}
|
|
776
|
-
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
// src/features/analysis/scm/utils/index.ts
|
|
869
|
+
function getFixUrlWithRedirect(params) {
|
|
870
|
+
const {
|
|
871
|
+
fixId,
|
|
872
|
+
projectId,
|
|
873
|
+
organizationId,
|
|
874
|
+
analysisId,
|
|
875
|
+
redirectUrl,
|
|
876
|
+
appBaseUrl,
|
|
877
|
+
commentId
|
|
878
|
+
} = params;
|
|
879
|
+
const searchParams = new URLSearchParams();
|
|
880
|
+
searchParams.append("commit_redirect_url", redirectUrl);
|
|
881
|
+
searchParams.append("comment_id", commentId.toString());
|
|
882
|
+
return `${getFixUrl({
|
|
883
|
+
appBaseUrl,
|
|
884
|
+
fixId,
|
|
885
|
+
projectId,
|
|
886
|
+
organizationId,
|
|
887
|
+
analysisId
|
|
888
|
+
})}?${searchParams.toString()}`;
|
|
777
889
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
890
|
+
function getFixUrl({
|
|
891
|
+
appBaseUrl,
|
|
892
|
+
fixId,
|
|
893
|
+
projectId,
|
|
894
|
+
organizationId,
|
|
895
|
+
analysisId
|
|
782
896
|
}) {
|
|
783
|
-
|
|
784
|
-
|
|
897
|
+
return `${appBaseUrl}/organization/${organizationId}/project/${projectId}/report/${analysisId}/fix/${fixId}`;
|
|
898
|
+
}
|
|
899
|
+
function getCommitUrl(params) {
|
|
900
|
+
const {
|
|
901
|
+
fixId,
|
|
902
|
+
projectId,
|
|
903
|
+
organizationId,
|
|
904
|
+
analysisId,
|
|
905
|
+
redirectUrl,
|
|
906
|
+
appBaseUrl,
|
|
907
|
+
commentId
|
|
908
|
+
} = params;
|
|
909
|
+
const searchParams = new URLSearchParams();
|
|
910
|
+
searchParams.append("redirect_url", redirectUrl);
|
|
911
|
+
searchParams.append("comment_id", commentId.toString());
|
|
912
|
+
return `${getFixUrl({
|
|
913
|
+
appBaseUrl,
|
|
914
|
+
fixId,
|
|
915
|
+
projectId,
|
|
916
|
+
organizationId,
|
|
917
|
+
analysisId
|
|
918
|
+
})}/commit?${searchParams.toString()}`;
|
|
919
|
+
}
|
|
920
|
+
var userNamePattern = /^(https?:\/\/)([^@]+@)?([^/]+\/.+)$/;
|
|
921
|
+
var sshPattern = /^git@([\w.-]+):([\w./-]+)$/;
|
|
922
|
+
function normalizeUrl(repoUrl) {
|
|
923
|
+
let trimmedUrl = repoUrl.trim().replace(/\/+$/, "");
|
|
924
|
+
if (repoUrl.endsWith(".git")) {
|
|
925
|
+
trimmedUrl = trimmedUrl.slice(0, -".git".length);
|
|
785
926
|
}
|
|
786
|
-
const
|
|
787
|
-
if (
|
|
788
|
-
const
|
|
789
|
-
|
|
927
|
+
const usernameMatch = trimmedUrl.match(userNamePattern);
|
|
928
|
+
if (usernameMatch) {
|
|
929
|
+
const [_all, protocol, _username, repoPath] = usernameMatch;
|
|
930
|
+
trimmedUrl = `${protocol}${repoPath}`;
|
|
790
931
|
}
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
}
|
|
795
|
-
async function adoValidateParams({
|
|
796
|
-
url,
|
|
797
|
-
accessToken,
|
|
798
|
-
tokenOrg
|
|
799
|
-
}) {
|
|
800
|
-
try {
|
|
801
|
-
if (!url && accessToken && getAdoTokenType(accessToken) === "OAUTH" /* OAUTH */) {
|
|
802
|
-
await _getOrgsForOauthToken({ oauthToken: accessToken });
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
let org = tokenOrg;
|
|
806
|
-
if (url) {
|
|
807
|
-
const { owner } = parseAdoOwnerAndRepo(url);
|
|
808
|
-
org = owner;
|
|
809
|
-
}
|
|
810
|
-
if (!org) {
|
|
811
|
-
throw new InvalidRepoUrlError(`invalid ADO ORG ${org}`);
|
|
812
|
-
}
|
|
813
|
-
const api2 = await getAdoApiClient({
|
|
814
|
-
accessToken,
|
|
815
|
-
tokenOrg,
|
|
816
|
-
orgName: org
|
|
817
|
-
});
|
|
818
|
-
await api2.connect();
|
|
819
|
-
} catch (e) {
|
|
820
|
-
const error = e;
|
|
821
|
-
const code = error.code || error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
|
|
822
|
-
const description = error.description || `${e}`;
|
|
823
|
-
if (code === 401 || code === 403 || description.includes("401") || description.includes("403")) {
|
|
824
|
-
throw new InvalidAccessTokenError(`invalid ADO access token`);
|
|
825
|
-
}
|
|
826
|
-
if (code === 404 || description.includes("404") || description.includes("Not Found")) {
|
|
827
|
-
throw new InvalidRepoUrlError(`invalid ADO repo URL ${url}`);
|
|
828
|
-
}
|
|
829
|
-
throw e;
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
async function getAdoIsUserCollaborator({
|
|
833
|
-
accessToken,
|
|
834
|
-
tokenOrg,
|
|
835
|
-
repoUrl
|
|
836
|
-
}) {
|
|
837
|
-
try {
|
|
838
|
-
const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
839
|
-
const api2 = await getAdoApiClient({
|
|
840
|
-
accessToken,
|
|
841
|
-
tokenOrg,
|
|
842
|
-
orgName: owner
|
|
843
|
-
});
|
|
844
|
-
const git = await api2.getGitApi();
|
|
845
|
-
const branches = await git.getBranches(repo, projectName);
|
|
846
|
-
if (!branches || branches.length === 0) {
|
|
847
|
-
throw new InvalidRepoUrlError("no branches");
|
|
848
|
-
}
|
|
849
|
-
return true;
|
|
850
|
-
} catch (e) {
|
|
851
|
-
return false;
|
|
932
|
+
const sshMatch = trimmedUrl.match(sshPattern);
|
|
933
|
+
if (sshMatch) {
|
|
934
|
+
const [_all, hostname, reporPath] = sshMatch;
|
|
935
|
+
trimmedUrl = `https://${hostname}/${reporPath}`;
|
|
852
936
|
}
|
|
937
|
+
return trimmedUrl;
|
|
853
938
|
}
|
|
854
|
-
var
|
|
855
|
-
|
|
856
|
-
2: "abandoned" /* abandoned */,
|
|
857
|
-
3: "completed" /* completed */,
|
|
858
|
-
4: "all" /* all */
|
|
939
|
+
var isUrlHasPath = (url) => {
|
|
940
|
+
return new URL(url).origin !== url;
|
|
859
941
|
};
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
tokenOrg,
|
|
863
|
-
repoUrl,
|
|
864
|
-
prNumber
|
|
865
|
-
}) {
|
|
866
|
-
const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
867
|
-
const api2 = await getAdoApiClient({
|
|
868
|
-
accessToken,
|
|
869
|
-
tokenOrg,
|
|
870
|
-
orgName: owner
|
|
871
|
-
});
|
|
872
|
-
const git = await api2.getGitApi();
|
|
873
|
-
const res = await git.getPullRequest(repo, prNumber, projectName);
|
|
874
|
-
if (!res.status || res.status < 1 || res.status > 3) {
|
|
875
|
-
throw new Error("bad pr status for ADO");
|
|
876
|
-
}
|
|
877
|
-
return adoStatusNumberToEnumMap[res.status];
|
|
878
|
-
}
|
|
879
|
-
async function getAdoIsRemoteBranch({
|
|
880
|
-
accessToken,
|
|
881
|
-
tokenOrg,
|
|
882
|
-
repoUrl,
|
|
883
|
-
branch
|
|
884
|
-
}) {
|
|
885
|
-
const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
886
|
-
const api2 = await getAdoApiClient({
|
|
887
|
-
accessToken,
|
|
888
|
-
tokenOrg,
|
|
889
|
-
orgName: owner
|
|
890
|
-
});
|
|
891
|
-
const git = await api2.getGitApi();
|
|
892
|
-
try {
|
|
893
|
-
const branchStatus = await git.getBranch(repo, branch, projectName);
|
|
894
|
-
if (!branchStatus || !branchStatus.commit) {
|
|
895
|
-
throw new InvalidRepoUrlError("no branch status");
|
|
896
|
-
}
|
|
897
|
-
return branchStatus.name === branch;
|
|
898
|
-
} catch (e) {
|
|
899
|
-
return false;
|
|
900
|
-
}
|
|
942
|
+
function shouldValidateUrl(repoUrl) {
|
|
943
|
+
return repoUrl && isUrlHasPath(repoUrl);
|
|
901
944
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
if (orgs.length === 0 && !orgName) {
|
|
912
|
-
throw new Error(`no orgs for ADO`);
|
|
913
|
-
} else if (orgs.length === 0 && orgName) {
|
|
914
|
-
orgs = [orgName];
|
|
915
|
-
}
|
|
916
|
-
const repos = (await Promise.allSettled(
|
|
917
|
-
orgs.map(async (org) => {
|
|
918
|
-
const orgApi = await getAdoApiClient({
|
|
919
|
-
accessToken,
|
|
920
|
-
tokenOrg,
|
|
921
|
-
orgName: org
|
|
922
|
-
});
|
|
923
|
-
const gitOrg = await orgApi.getGitApi();
|
|
924
|
-
const orgRepos = await gitOrg.getRepositories();
|
|
925
|
-
const repoInfoList = (await Promise.allSettled(
|
|
926
|
-
orgRepos.map(async (repo) => {
|
|
927
|
-
if (!repo.name || !repo.remoteUrl || !repo.defaultBranch) {
|
|
928
|
-
throw new InvalidRepoUrlError("bad repo");
|
|
929
|
-
}
|
|
930
|
-
const branch = await gitOrg.getBranch(
|
|
931
|
-
repo.name,
|
|
932
|
-
repo.defaultBranch.replace(/^refs\/heads\//, ""),
|
|
933
|
-
repo.project?.name
|
|
934
|
-
);
|
|
935
|
-
return {
|
|
936
|
-
repoName: repo.name,
|
|
937
|
-
repoUrl: repo.remoteUrl.replace(
|
|
938
|
-
/^[hH][tT][tT][pP][sS]:\/\/[^/]+@/,
|
|
939
|
-
"https://"
|
|
940
|
-
),
|
|
941
|
-
repoOwner: org,
|
|
942
|
-
repoIsPublic: repo.project?.visibility === 2,
|
|
943
|
-
//2 is public in the ADO API
|
|
944
|
-
repoLanguages: [],
|
|
945
|
-
repoUpdatedAt: branch.commit?.committer?.date?.toDateString() || repo.project?.lastUpdateTime?.toDateString() || (/* @__PURE__ */ new Date()).toDateString()
|
|
946
|
-
};
|
|
947
|
-
})
|
|
948
|
-
)).reduce((acc, res) => {
|
|
949
|
-
if (res.status === "fulfilled") {
|
|
950
|
-
acc.push(res.value);
|
|
951
|
-
}
|
|
952
|
-
return acc;
|
|
953
|
-
}, []);
|
|
954
|
-
return repoInfoList;
|
|
945
|
+
|
|
946
|
+
// src/features/analysis/scm/bitbucket/bitbucket.ts
|
|
947
|
+
var BITBUCKET_HOSTNAME = "bitbucket.org";
|
|
948
|
+
var TokenExpiredErrorZ = z3.object({
|
|
949
|
+
status: z3.number(),
|
|
950
|
+
error: z3.object({
|
|
951
|
+
type: z3.string(),
|
|
952
|
+
error: z3.object({
|
|
953
|
+
message: z3.string()
|
|
955
954
|
})
|
|
956
|
-
)
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
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`;
|
|
955
|
+
})
|
|
956
|
+
});
|
|
957
|
+
var BITBUCKET_ACCESS_TOKEN_URL = `https://${BITBUCKET_HOSTNAME}/site/oauth2/access_token`;
|
|
958
|
+
var BitbucketAuthResultZ = z3.object({
|
|
959
|
+
access_token: z3.string(),
|
|
960
|
+
token_type: z3.string(),
|
|
961
|
+
refresh_token: z3.string()
|
|
962
|
+
});
|
|
963
|
+
var BitbucketParseResultZ = z3.object({
|
|
964
|
+
organization: z3.string(),
|
|
965
|
+
repoName: z3.string(),
|
|
966
|
+
hostname: z3.literal(BITBUCKET_HOSTNAME)
|
|
967
|
+
});
|
|
968
|
+
function parseBitbucketOrganizationAndRepo(bitbucketUrl) {
|
|
969
|
+
const parsedGitHubUrl = normalizeUrl(bitbucketUrl);
|
|
970
|
+
const parsingResult = parseScmURL(parsedGitHubUrl, "Bitbucket" /* Bitbucket */);
|
|
971
|
+
const validatedBitbucketResult = BitbucketParseResultZ.parse(parsingResult);
|
|
972
|
+
return {
|
|
973
|
+
workspace: validatedBitbucketResult.organization,
|
|
974
|
+
repoSlug: validatedBitbucketResult.repoName
|
|
975
|
+
};
|
|
978
976
|
}
|
|
979
|
-
async function
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
if (!a.commit?.committer?.date || !b.commit?.committer?.date) {
|
|
995
|
-
return 0;
|
|
996
|
-
}
|
|
997
|
-
return b.commit?.committer?.date.getTime() - a.commit?.committer?.date.getTime();
|
|
998
|
-
});
|
|
999
|
-
return res.reduce((acc, branch) => {
|
|
1000
|
-
if (!branch.name) {
|
|
1001
|
-
return acc;
|
|
977
|
+
async function getBitbucketToken(params) {
|
|
978
|
+
const { bitbucketClientId, bitbucketClientSecret, authType } = params;
|
|
979
|
+
const res = await fetch(BITBUCKET_ACCESS_TOKEN_URL, {
|
|
980
|
+
method: "POST",
|
|
981
|
+
headers: {
|
|
982
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
983
|
+
Authorization: "Basic " + btoa(`${bitbucketClientId}:${bitbucketClientSecret}`)
|
|
984
|
+
},
|
|
985
|
+
body: querystring.stringify(
|
|
986
|
+
authType === "refresh_token" ? {
|
|
987
|
+
grant_type: authType,
|
|
988
|
+
refresh_token: params.refreshToken
|
|
989
|
+
} : {
|
|
990
|
+
grant_type: authType,
|
|
991
|
+
code: params.code
|
|
1002
992
|
}
|
|
1003
|
-
|
|
1004
|
-
return acc;
|
|
1005
|
-
}, []);
|
|
1006
|
-
} catch (e) {
|
|
1007
|
-
return [];
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
async function createAdoPullRequest(options) {
|
|
1011
|
-
const { owner, repo, projectName } = parseAdoOwnerAndRepo(options.repoUrl);
|
|
1012
|
-
const api2 = await getAdoApiClient({
|
|
1013
|
-
accessToken: options.accessToken,
|
|
1014
|
-
tokenOrg: options.tokenOrg,
|
|
1015
|
-
orgName: owner
|
|
993
|
+
)
|
|
1016
994
|
});
|
|
1017
|
-
const
|
|
1018
|
-
|
|
1019
|
-
{
|
|
1020
|
-
sourceRefName: `refs/heads/${options.sourceBranchName}`,
|
|
1021
|
-
targetRefName: `refs/heads/${options.targetBranchName}`,
|
|
1022
|
-
title: options.title,
|
|
1023
|
-
description: options.body
|
|
1024
|
-
},
|
|
1025
|
-
repo,
|
|
1026
|
-
projectName
|
|
1027
|
-
);
|
|
1028
|
-
return res.pullRequestId;
|
|
995
|
+
const authResult = await res.json();
|
|
996
|
+
return BitbucketAuthResultZ.parse(authResult);
|
|
1029
997
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
projectName ? decodeURI(projectName) : void 0
|
|
1045
|
-
);
|
|
1046
|
-
if (!getRepositoryRes?.defaultBranch) {
|
|
1047
|
-
throw new InvalidRepoUrlError("no default branch");
|
|
998
|
+
function getBitbucketIntance(params) {
|
|
999
|
+
const BitbucketContstructor = bitbucketPkg && "Bitbucket" in bitbucketPkg ? bitbucketPkg.Bitbucket : bitbucketPkgNode.Bitbucket;
|
|
1000
|
+
switch (params.authType) {
|
|
1001
|
+
case "public":
|
|
1002
|
+
return new BitbucketContstructor();
|
|
1003
|
+
case "token":
|
|
1004
|
+
return new BitbucketContstructor({ auth: { token: params.token } });
|
|
1005
|
+
case "basic":
|
|
1006
|
+
return new BitbucketContstructor({
|
|
1007
|
+
auth: {
|
|
1008
|
+
password: params.password,
|
|
1009
|
+
username: params.username
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1048
1012
|
}
|
|
1049
|
-
return getRepositoryRes.defaultBranch.replace("refs/heads/", "");
|
|
1050
1013
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
sha: res.commit.commitId,
|
|
1075
|
-
type: "BRANCH" /* BRANCH */,
|
|
1076
|
-
date: res.commit.committer?.date || /* @__PURE__ */ new Date()
|
|
1077
|
-
};
|
|
1078
|
-
})(),
|
|
1079
|
-
(async () => {
|
|
1080
|
-
const res = await git.getCommits(
|
|
1081
|
-
repo,
|
|
1082
|
-
{
|
|
1083
|
-
fromCommitId: ref,
|
|
1084
|
-
toCommitId: ref,
|
|
1085
|
-
$top: 1
|
|
1086
|
-
},
|
|
1087
|
-
projectName
|
|
1014
|
+
function getBitbucketSdk(params) {
|
|
1015
|
+
const bitbucketClient = getBitbucketIntance(params);
|
|
1016
|
+
return {
|
|
1017
|
+
getAuthType() {
|
|
1018
|
+
return params.authType;
|
|
1019
|
+
},
|
|
1020
|
+
async getRepos(params2) {
|
|
1021
|
+
const repoRes = params2?.workspaceSlug ? await getRepositoriesByWorkspace(bitbucketClient, {
|
|
1022
|
+
workspaceSlug: params2.workspaceSlug
|
|
1023
|
+
}) : await getllUsersrepositories(bitbucketClient);
|
|
1024
|
+
return repoRes.map((repo) => ({
|
|
1025
|
+
repoIsPublic: !repo.is_private,
|
|
1026
|
+
repoName: repo.name || "unknown repo name",
|
|
1027
|
+
repoOwner: repo.owner?.username || "unknown owner",
|
|
1028
|
+
// language can be empty string
|
|
1029
|
+
repoLanguages: repo.language ? [repo.language] : [],
|
|
1030
|
+
repoUpdatedAt: repo.updated_on ? repo.updated_on : (/* @__PURE__ */ new Date()).toISOString(),
|
|
1031
|
+
repoUrl: repo.links?.html?.href || ""
|
|
1032
|
+
}));
|
|
1033
|
+
},
|
|
1034
|
+
async getBranchList(params2) {
|
|
1035
|
+
const { workspace, repoSlug } = parseBitbucketOrganizationAndRepo(
|
|
1036
|
+
params2.repoUrl
|
|
1088
1037
|
);
|
|
1089
|
-
const
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
type: "COMMIT" /* COMMIT */,
|
|
1096
|
-
date: commit.committer?.date || /* @__PURE__ */ new Date()
|
|
1097
|
-
};
|
|
1098
|
-
})(),
|
|
1099
|
-
(async () => {
|
|
1100
|
-
const res = await git.getRefs(repo, projectName, `tags/${ref}`);
|
|
1101
|
-
if (!res[0] || !res[0].objectId) {
|
|
1102
|
-
throw new Error("no tag ref");
|
|
1038
|
+
const res = await bitbucketClient.refs.listBranches({
|
|
1039
|
+
repo_slug: repoSlug,
|
|
1040
|
+
workspace
|
|
1041
|
+
});
|
|
1042
|
+
if (!res.data.values) {
|
|
1043
|
+
return [];
|
|
1103
1044
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1045
|
+
return res.data.values.filter((branch) => !!branch.name).map((branch) => z3.string().parse(branch.name));
|
|
1046
|
+
},
|
|
1047
|
+
async getIsUserCollaborator(params2) {
|
|
1048
|
+
const { repoUrl } = params2;
|
|
1049
|
+
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(repoUrl);
|
|
1050
|
+
const fullRepoName = `${workspace}/${repoSlug}`;
|
|
1051
|
+
const res = await bitbucketClient.user.listPermissionsForRepos({
|
|
1052
|
+
q: `repository.full_name~"${fullRepoName}"`
|
|
1053
|
+
});
|
|
1054
|
+
return res.data.values?.some(
|
|
1055
|
+
(res2) => res2.repository?.full_name === fullRepoName
|
|
1056
|
+
) ?? false;
|
|
1057
|
+
},
|
|
1058
|
+
async createPullRequest(params2) {
|
|
1059
|
+
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
1060
|
+
params2.repoUrl
|
|
1061
|
+
);
|
|
1062
|
+
const res = await bitbucketClient.pullrequests.create({
|
|
1063
|
+
repo_slug: repoSlug,
|
|
1064
|
+
workspace,
|
|
1065
|
+
_body: {
|
|
1066
|
+
type: "pullrequest",
|
|
1067
|
+
title: params2.title,
|
|
1068
|
+
summary: {
|
|
1069
|
+
raw: params2.body
|
|
1070
|
+
},
|
|
1071
|
+
source: {
|
|
1072
|
+
branch: {
|
|
1073
|
+
name: params2.sourceBranchName
|
|
1074
|
+
}
|
|
1075
|
+
},
|
|
1076
|
+
destination: {
|
|
1077
|
+
branch: {
|
|
1078
|
+
name: params2.targetBranchName
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1109
1081
|
}
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
toCommitId: objectId,
|
|
1117
|
-
$top: 1
|
|
1118
|
-
},
|
|
1119
|
-
projectName
|
|
1082
|
+
});
|
|
1083
|
+
return res.data;
|
|
1084
|
+
},
|
|
1085
|
+
async getDownloadlink(params2) {
|
|
1086
|
+
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
1087
|
+
params2.repoUrl
|
|
1120
1088
|
);
|
|
1121
|
-
const
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
}
|
|
1125
|
-
return
|
|
1126
|
-
|
|
1089
|
+
const res = await bitbucketClient.downloads.list({
|
|
1090
|
+
repo_slug: repoSlug,
|
|
1091
|
+
workspace
|
|
1092
|
+
});
|
|
1093
|
+
return res.data;
|
|
1094
|
+
},
|
|
1095
|
+
async getBranch(params2) {
|
|
1096
|
+
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
1097
|
+
params2.repoUrl
|
|
1098
|
+
);
|
|
1099
|
+
const res = await bitbucketClient.refs.getBranch({
|
|
1100
|
+
name: params2.branchName,
|
|
1101
|
+
repo_slug: repoSlug,
|
|
1102
|
+
workspace
|
|
1103
|
+
});
|
|
1104
|
+
return res.data;
|
|
1105
|
+
},
|
|
1106
|
+
async getRepo(params2) {
|
|
1107
|
+
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
1108
|
+
params2.repoUrl
|
|
1109
|
+
);
|
|
1110
|
+
const res = await bitbucketClient.repositories.get({
|
|
1111
|
+
repo_slug: repoSlug,
|
|
1112
|
+
workspace
|
|
1113
|
+
});
|
|
1114
|
+
return res.data;
|
|
1115
|
+
},
|
|
1116
|
+
async getCommit(params2) {
|
|
1117
|
+
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
1118
|
+
params2.repoUrl
|
|
1119
|
+
);
|
|
1120
|
+
const res = await bitbucketClient.commits.get({
|
|
1121
|
+
commit: params2.commitSha,
|
|
1122
|
+
repo_slug: repoSlug,
|
|
1123
|
+
workspace
|
|
1124
|
+
});
|
|
1125
|
+
return res.data;
|
|
1126
|
+
},
|
|
1127
|
+
async getUser() {
|
|
1128
|
+
const res = await bitbucketClient.user.get({});
|
|
1129
|
+
return res.data;
|
|
1130
|
+
},
|
|
1131
|
+
async getReferenceData({
|
|
1132
|
+
ref,
|
|
1133
|
+
url
|
|
1134
|
+
}) {
|
|
1135
|
+
return Promise.allSettled([
|
|
1136
|
+
this.getTagRef({ repoUrl: url, tagName: ref }),
|
|
1137
|
+
this.getBranchRef({ repoUrl: url, branchName: ref }),
|
|
1138
|
+
this.getCommitRef({ repoUrl: url, commitSha: ref })
|
|
1139
|
+
]).then((promisesResult) => {
|
|
1140
|
+
const [refPromise] = promisesResult.filter(
|
|
1141
|
+
(promise) => promise.status === "fulfilled"
|
|
1142
|
+
);
|
|
1143
|
+
if (!refPromise) {
|
|
1144
|
+
throw new RefNotFoundError(`Invalid reference ${ref} for ${url}`);
|
|
1145
|
+
}
|
|
1146
|
+
return refPromise.value;
|
|
1147
|
+
});
|
|
1148
|
+
},
|
|
1149
|
+
async getTagRef(params2) {
|
|
1150
|
+
const { tagName, repoUrl } = params2;
|
|
1151
|
+
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(repoUrl);
|
|
1152
|
+
const tagRes = await bitbucketClient.refs.getTag({
|
|
1153
|
+
repo_slug: repoSlug,
|
|
1154
|
+
workspace,
|
|
1155
|
+
name: tagName
|
|
1156
|
+
});
|
|
1157
|
+
return GetRefererenceResultZ.parse({
|
|
1158
|
+
sha: tagRes.data.target?.hash,
|
|
1127
1159
|
type: "TAG" /* TAG */,
|
|
1128
|
-
date:
|
|
1129
|
-
};
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1160
|
+
date: new Date(z3.string().parse(tagRes.data.target?.date))
|
|
1161
|
+
});
|
|
1162
|
+
},
|
|
1163
|
+
async getBranchRef(params2) {
|
|
1164
|
+
const getBranchRes = await this.getBranch(params2);
|
|
1165
|
+
return GetRefererenceResultZ.parse({
|
|
1166
|
+
sha: getBranchRes.target?.hash,
|
|
1167
|
+
type: "BRANCH" /* BRANCH */,
|
|
1168
|
+
date: new Date(z3.string().parse(getBranchRes.target?.date))
|
|
1169
|
+
});
|
|
1170
|
+
},
|
|
1171
|
+
async getCommitRef(params2) {
|
|
1172
|
+
const getCommitRes = await this.getCommit(params2);
|
|
1173
|
+
return GetRefererenceResultZ.parse({
|
|
1174
|
+
sha: getCommitRes.hash,
|
|
1175
|
+
type: "COMMIT" /* COMMIT */,
|
|
1176
|
+
date: new Date(z3.string().parse(getCommitRes.date))
|
|
1177
|
+
});
|
|
1178
|
+
},
|
|
1179
|
+
async getDownloadUrl({ url, sha }) {
|
|
1180
|
+
this.getReferenceData({ ref: sha, url });
|
|
1181
|
+
const repoRes = await this.getRepo({ repoUrl: url });
|
|
1182
|
+
const parsedRepoUrl = z3.string().url().parse(repoRes.links?.html?.href);
|
|
1183
|
+
return `${parsedRepoUrl}/get/${sha}.zip`;
|
|
1184
|
+
},
|
|
1185
|
+
async getPullRequest(params2) {
|
|
1186
|
+
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
1187
|
+
params2.url
|
|
1188
|
+
);
|
|
1189
|
+
const res = await bitbucketClient.pullrequests.get({
|
|
1190
|
+
pull_request_id: params2.prNumber,
|
|
1191
|
+
repo_slug: repoSlug,
|
|
1192
|
+
workspace
|
|
1193
|
+
});
|
|
1194
|
+
return res.data;
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1143
1197
|
}
|
|
1144
|
-
function
|
|
1145
|
-
|
|
1146
|
-
const
|
|
1147
|
-
|
|
1148
|
-
|
|
1198
|
+
async function validateBitbucketParams(params) {
|
|
1199
|
+
const { bitbucketClient } = params;
|
|
1200
|
+
const authType = bitbucketClient.getAuthType();
|
|
1201
|
+
try {
|
|
1202
|
+
if (authType !== "public") {
|
|
1203
|
+
await bitbucketClient.getUser();
|
|
1204
|
+
}
|
|
1205
|
+
if (params.url && shouldValidateUrl(params.url)) {
|
|
1206
|
+
await bitbucketClient.getRepo({ repoUrl: params.url });
|
|
1207
|
+
}
|
|
1208
|
+
} catch (e) {
|
|
1209
|
+
const safeParseError = TokenExpiredErrorZ.safeParse(e);
|
|
1210
|
+
if (safeParseError.success) {
|
|
1211
|
+
switch (safeParseError.data.status) {
|
|
1212
|
+
case 401:
|
|
1213
|
+
throw new InvalidAccessTokenError(
|
|
1214
|
+
safeParseError.data.error.error.message
|
|
1215
|
+
);
|
|
1216
|
+
case 404:
|
|
1217
|
+
throw new InvalidRepoUrlError(safeParseError.data.error.error.message);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
throw e;
|
|
1149
1221
|
}
|
|
1150
|
-
const { organization, repoName, projectName, projectPath, pathElements } = parsingResult;
|
|
1151
|
-
return {
|
|
1152
|
-
owner: decodeURI(organization),
|
|
1153
|
-
repo: decodeURI(repoName),
|
|
1154
|
-
projectName: projectName ? decodeURI(projectName) : void 0,
|
|
1155
|
-
projectPath,
|
|
1156
|
-
pathElements
|
|
1157
|
-
};
|
|
1158
1222
|
}
|
|
1159
|
-
async function
|
|
1160
|
-
|
|
1223
|
+
async function getUsersworkspacesSlugs(bitbucketClient) {
|
|
1224
|
+
const res = await bitbucketClient.workspaces.getWorkspaces({});
|
|
1225
|
+
return res.data.values?.map((v) => z3.string().parse(v.slug));
|
|
1161
1226
|
}
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
client_assertion: adoClientSecret,
|
|
1183
|
-
redirect_uri: redirectUri,
|
|
1184
|
-
assertion: token,
|
|
1185
|
-
grant_type: tokenType === "code" /* CODE */ ? "urn:ietf:params:oauth:grant-type:jwt-bearer" : "refresh_token"
|
|
1186
|
-
})
|
|
1227
|
+
async function getllUsersrepositories(bitbucketClient) {
|
|
1228
|
+
const userWorspacesSlugs = await getUsersworkspacesSlugs(bitbucketClient);
|
|
1229
|
+
if (!userWorspacesSlugs) {
|
|
1230
|
+
return [];
|
|
1231
|
+
}
|
|
1232
|
+
const allWorkspaceRepos = [];
|
|
1233
|
+
for (const workspaceSlug of userWorspacesSlugs) {
|
|
1234
|
+
const repos = await bitbucketClient.repositories.list({
|
|
1235
|
+
workspace: workspaceSlug
|
|
1236
|
+
});
|
|
1237
|
+
if (!repos.data.values) {
|
|
1238
|
+
continue;
|
|
1239
|
+
}
|
|
1240
|
+
allWorkspaceRepos.push(...repos.data.values);
|
|
1241
|
+
}
|
|
1242
|
+
return allWorkspaceRepos;
|
|
1243
|
+
}
|
|
1244
|
+
async function getRepositoriesByWorkspace(bitbucketClient, { workspaceSlug }) {
|
|
1245
|
+
const res = await bitbucketClient.repositories.list({
|
|
1246
|
+
workspace: workspaceSlug
|
|
1187
1247
|
});
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
}
|
|
1191
|
-
var AdoSdk = {
|
|
1192
|
-
getAdoApiClient,
|
|
1193
|
-
adoValidateParams,
|
|
1194
|
-
getAdoIsUserCollaborator,
|
|
1195
|
-
getAdoPullRequestStatus,
|
|
1196
|
-
getAdoIsRemoteBranch,
|
|
1197
|
-
getAdoRepoList,
|
|
1198
|
-
getAdoDownloadUrl,
|
|
1199
|
-
getAdoBranchList,
|
|
1200
|
-
createAdoPullRequest,
|
|
1201
|
-
getAdoRepoDefaultBranch,
|
|
1202
|
-
getAdoReferenceData,
|
|
1203
|
-
parseAdoOwnerAndRepo,
|
|
1204
|
-
getAdoBlameRanges,
|
|
1205
|
-
getAdoToken,
|
|
1206
|
-
getAdoTokenType
|
|
1207
|
-
};
|
|
1208
|
-
|
|
1209
|
-
// src/features/analysis/scm/bitbucket/bitbucket.ts
|
|
1210
|
-
import querystring3 from "node:querystring";
|
|
1211
|
-
import * as bitbucketPkg from "bitbucket";
|
|
1212
|
-
import { z as z8 } from "zod";
|
|
1213
|
-
|
|
1214
|
-
// src/features/analysis/scm/scm.ts
|
|
1215
|
-
import { z as z7 } from "zod";
|
|
1248
|
+
return res.data.values ?? [];
|
|
1249
|
+
}
|
|
1216
1250
|
|
|
1217
1251
|
// src/features/analysis/scm/github/github.ts
|
|
1218
1252
|
import { RequestError } from "@octokit/request-error";
|
|
@@ -1303,7 +1337,7 @@ function isGithubOnPrem(url) {
|
|
|
1303
1337
|
function getFetch(url) {
|
|
1304
1338
|
if (url && BROKERED_HOSTS.includes(new URL(url).origin)) {
|
|
1305
1339
|
const dispatcher = new ProxyAgent({
|
|
1306
|
-
uri:
|
|
1340
|
+
uri: GIT_PROXY_HOST,
|
|
1307
1341
|
requestTls: {
|
|
1308
1342
|
rejectUnauthorized: false
|
|
1309
1343
|
}
|
|
@@ -1727,226 +1761,6 @@ import {
|
|
|
1727
1761
|
} from "@gitbeaker/rest";
|
|
1728
1762
|
import { ProxyAgent as ProxyAgent2 } from "undici";
|
|
1729
1763
|
|
|
1730
|
-
// src/features/analysis/scm/env.ts
|
|
1731
|
-
import { z as z3 } from "zod";
|
|
1732
|
-
var EnvVariablesZod = z3.object({
|
|
1733
|
-
GITLAB_API_TOKEN: z3.string().optional(),
|
|
1734
|
-
BROKERED_HOSTS: z3.string().toLowerCase().transform(
|
|
1735
|
-
(x) => x.split(",").map((url) => url.trim(), []).filter(Boolean)
|
|
1736
|
-
).default(""),
|
|
1737
|
-
GITHUB_API_TOKEN: z3.string().optional()
|
|
1738
|
-
});
|
|
1739
|
-
var { GITLAB_API_TOKEN, BROKERED_HOSTS, GITHUB_API_TOKEN } = EnvVariablesZod.parse(process.env);
|
|
1740
|
-
|
|
1741
|
-
// src/features/analysis/scm/utils/get_issue_type.ts
|
|
1742
|
-
var getIssueType = (issueType) => {
|
|
1743
|
-
switch (issueType) {
|
|
1744
|
-
case "SQL_Injection" /* SqlInjection */:
|
|
1745
|
-
return "SQL Injection";
|
|
1746
|
-
case "CMDi_relative_path_command" /* CmDiRelativePathCommand */:
|
|
1747
|
-
return "Relative Path Command Injection";
|
|
1748
|
-
case "CMDi" /* CmDi */:
|
|
1749
|
-
return "Command Injection";
|
|
1750
|
-
case "XXE" /* Xxe */:
|
|
1751
|
-
return "XXE";
|
|
1752
|
-
case "XSS" /* Xss */:
|
|
1753
|
-
return "XSS";
|
|
1754
|
-
case "PT" /* Pt */:
|
|
1755
|
-
return "Path Traversal";
|
|
1756
|
-
case "ZIP_SLIP" /* ZipSlip */:
|
|
1757
|
-
return "Zip Slip";
|
|
1758
|
-
case "INSECURE_RANDOMNESS" /* InsecureRandomness */:
|
|
1759
|
-
return "Insecure Randomness";
|
|
1760
|
-
case "SSRF" /* Ssrf */:
|
|
1761
|
-
return "Server Side Request Forgery";
|
|
1762
|
-
case "TYPE_CONFUSION" /* TypeConfusion */:
|
|
1763
|
-
return "Type Confusion";
|
|
1764
|
-
case "REGEX_INJECTION" /* RegexInjection */:
|
|
1765
|
-
return "Regular Expression Injection";
|
|
1766
|
-
case "INCOMPLETE_URL_SANITIZATION" /* IncompleteUrlSanitization */:
|
|
1767
|
-
return "Incomplete URL Sanitization";
|
|
1768
|
-
case "LOCALE_DEPENDENT_COMPARISON" /* LocaleDependentComparison */:
|
|
1769
|
-
return "Locale Dependent Comparison";
|
|
1770
|
-
case "LOG_FORGING" /* LogForging */:
|
|
1771
|
-
return "Log Forging";
|
|
1772
|
-
case "MISSING_CHECK_AGAINST_NULL" /* MissingCheckAgainstNull */:
|
|
1773
|
-
return "Missing Check against Null";
|
|
1774
|
-
case "PASSWORD_IN_COMMENT" /* PasswordInComment */:
|
|
1775
|
-
return "Password in Comment";
|
|
1776
|
-
case "OVERLY_BROAD_CATCH" /* OverlyBroadCatch */:
|
|
1777
|
-
return "Poor Error Handling: Overly Broad Catch";
|
|
1778
|
-
case "USE_OF_SYSTEM_OUTPUT_STREAM" /* UseOfSystemOutputStream */:
|
|
1779
|
-
return "Use of System.out/System.err";
|
|
1780
|
-
case "DANGEROUS_FUNCTION_OVERFLOW" /* DangerousFunctionOverflow */:
|
|
1781
|
-
return "Use of dangerous function";
|
|
1782
|
-
case "DOS_STRING_BUILDER" /* DosStringBuilder */:
|
|
1783
|
-
return "Denial of Service: StringBuilder";
|
|
1784
|
-
case "OPEN_REDIRECT" /* OpenRedirect */:
|
|
1785
|
-
return "Open Redirect";
|
|
1786
|
-
case "WEAK_XML_SCHEMA_UNBOUNDED_OCCURRENCES" /* WeakXmlSchemaUnboundedOccurrences */:
|
|
1787
|
-
return "Weak XML Schema: Unbounded Occurrences";
|
|
1788
|
-
case "SYSTEM_INFORMATION_LEAK" /* SystemInformationLeak */:
|
|
1789
|
-
return "System Information Leak";
|
|
1790
|
-
case "SYSTEM_INFORMATION_LEAK_EXTERNAL" /* SystemInformationLeakExternal */:
|
|
1791
|
-
return "External System Information Leak";
|
|
1792
|
-
case "HTTP_RESPONSE_SPLITTING" /* HttpResponseSplitting */:
|
|
1793
|
-
return "HTTP response splitting";
|
|
1794
|
-
case "HTTP_ONLY_COOKIE" /* HttpOnlyCookie */:
|
|
1795
|
-
return "Cookie is not HttpOnly";
|
|
1796
|
-
case "INSECURE_COOKIE" /* InsecureCookie */:
|
|
1797
|
-
return "Insecure Cookie";
|
|
1798
|
-
case "TRUST_BOUNDARY_VIOLATION" /* TrustBoundaryViolation */:
|
|
1799
|
-
return "Trust Boundary Violation";
|
|
1800
|
-
case "NULL_DEREFERENCE" /* NullDereference */:
|
|
1801
|
-
return "Null Dereference";
|
|
1802
|
-
case "UNSAFE_DESERIALIZATION" /* UnsafeDeserialization */:
|
|
1803
|
-
return "Unsafe deserialization";
|
|
1804
|
-
case "INSECURE_BINDER_CONFIGURATION" /* InsecureBinderConfiguration */:
|
|
1805
|
-
return "Insecure Binder Configuration";
|
|
1806
|
-
case "UNSAFE_TARGET_BLANK" /* UnsafeTargetBlank */:
|
|
1807
|
-
return "Unsafe use of target blank";
|
|
1808
|
-
case "IFRAME_WITHOUT_SANDBOX" /* IframeWithoutSandbox */:
|
|
1809
|
-
return "Client use of iframe without sandbox";
|
|
1810
|
-
case "JQUERY_DEPRECATED_SYMBOLS" /* JqueryDeprecatedSymbols */:
|
|
1811
|
-
return "jQuery deprecated symbols";
|
|
1812
|
-
case "MISSING_ANTIFORGERY_VALIDATION" /* MissingAntiforgeryValidation */:
|
|
1813
|
-
return "Missing Anti-Forgery Validation";
|
|
1814
|
-
case "GRAPHQL_DEPTH_LIMIT" /* GraphqlDepthLimit */:
|
|
1815
|
-
return "GraphQL Depth Limit";
|
|
1816
|
-
case "UNCHECKED_LOOP_CONDITION" /* UncheckedLoopCondition */:
|
|
1817
|
-
return "Unchecked Loop Condition";
|
|
1818
|
-
case "IMPROPER_RESOURCE_SHUTDOWN_OR_RELEASE" /* ImproperResourceShutdownOrRelease */:
|
|
1819
|
-
return "Improper Resource Shutdown or Release";
|
|
1820
|
-
case "IMPROPER_EXCEPTION_HANDLING" /* ImproperExceptionHandling */:
|
|
1821
|
-
return "Improper Exception Handling";
|
|
1822
|
-
case "DEFAULT_RIGHTS_IN_OBJ_DEFINITION" /* DefaultRightsInObjDefinition */:
|
|
1823
|
-
return "Default Definer Rights in Package or Object Definition";
|
|
1824
|
-
case "HTML_COMMENT_IN_JSP" /* HtmlCommentInJsp */:
|
|
1825
|
-
return "HTML Comment in JSP";
|
|
1826
|
-
case "ERROR_CONDTION_WITHOUT_ACTION" /* ErrorCondtionWithoutAction */:
|
|
1827
|
-
return "Error Condition Without Action";
|
|
1828
|
-
case "DEPRECATED_FUNCTION" /* DeprecatedFunction */:
|
|
1829
|
-
return "Deprecated Function";
|
|
1830
|
-
case "HARDCODED_SECRETS" /* HardcodedSecrets */:
|
|
1831
|
-
return "Hardcoded Secrets";
|
|
1832
|
-
case "PROTOTYPE_POLLUTION" /* PrototypePollution */:
|
|
1833
|
-
return "Prototype Pollution";
|
|
1834
|
-
case "RACE_CONDITION_FORMAT_FLAW" /* RaceConditionFormatFlaw */:
|
|
1835
|
-
return "Race Condition Format Flaw";
|
|
1836
|
-
case "NON_FINAL_PUBLIC_STATIC_FIELD" /* NonFinalPublicStaticField */:
|
|
1837
|
-
return "Non-final Public Static Field";
|
|
1838
|
-
case "MISSING_HSTS_HEADER" /* MissingHstsHeader */:
|
|
1839
|
-
return "Missing HSTS Header";
|
|
1840
|
-
case "DEAD_CODE_UNUSED_FIELD" /* DeadCodeUnusedField */:
|
|
1841
|
-
return "Dead Code: Unused Field";
|
|
1842
|
-
case "HEADER_MANIPULATION" /* HeaderManipulation */:
|
|
1843
|
-
return "Header Manipulation";
|
|
1844
|
-
case "MISSING_EQUALS_OR_HASHCODE" /* MissingEqualsOrHashcode */:
|
|
1845
|
-
return "Missing equals or hashcode method";
|
|
1846
|
-
case "WCF_MISCONFIGURATION_INSUFFICIENT_LOGGING" /* WcfMisconfigurationInsufficientLogging */:
|
|
1847
|
-
return "WCF Misconfiguration: Insufficient Logging";
|
|
1848
|
-
case "WCF_MISCONFIGURATION_THROTTLING_NOT_ENABLED" /* WcfMisconfigurationThrottlingNotEnabled */:
|
|
1849
|
-
return "WCF Misconfiguration: Throttling Not Enabled";
|
|
1850
|
-
case "USELESS_REGEXP_CHAR_ESCAPE" /* UselessRegexpCharEscape */:
|
|
1851
|
-
return "Useless regular-expression character escape";
|
|
1852
|
-
case "INCOMPLETE_HOSTNAME_REGEX" /* IncompleteHostnameRegex */:
|
|
1853
|
-
return "Incomplete Hostname Regex";
|
|
1854
|
-
case "OVERLY_LARGE_RANGE" /* OverlyLargeRange */:
|
|
1855
|
-
return "Regex: Overly Large Range";
|
|
1856
|
-
case "INSUFFICIENT_LOGGING" /* InsufficientLogging */:
|
|
1857
|
-
return "Insufficient Logging of Sensitive Operations";
|
|
1858
|
-
case "PRIVACY_VIOLATION" /* PrivacyViolation */:
|
|
1859
|
-
return "Privacy Violation";
|
|
1860
|
-
case "INCOMPLETE_URL_SCHEME_CHECK" /* IncompleteUrlSchemeCheck */:
|
|
1861
|
-
return "Incomplete URL Scheme Check";
|
|
1862
|
-
case "VALUE_NEVER_READ" /* ValueNeverRead */:
|
|
1863
|
-
return "Value Never Read";
|
|
1864
|
-
case "VALUE_SHADOWING" /* ValueShadowing */:
|
|
1865
|
-
return "Value Shadowing";
|
|
1866
|
-
default: {
|
|
1867
|
-
return issueType ? issueType.replaceAll("_", " ") : "Other";
|
|
1868
|
-
}
|
|
1869
|
-
}
|
|
1870
|
-
};
|
|
1871
|
-
|
|
1872
|
-
// src/features/analysis/scm/utils/index.ts
|
|
1873
|
-
function getFixUrlWithRedirect(params) {
|
|
1874
|
-
const {
|
|
1875
|
-
fixId,
|
|
1876
|
-
projectId,
|
|
1877
|
-
organizationId,
|
|
1878
|
-
analysisId,
|
|
1879
|
-
redirectUrl,
|
|
1880
|
-
appBaseUrl,
|
|
1881
|
-
commentId
|
|
1882
|
-
} = params;
|
|
1883
|
-
const searchParams = new URLSearchParams();
|
|
1884
|
-
searchParams.append("commit_redirect_url", redirectUrl);
|
|
1885
|
-
searchParams.append("comment_id", commentId.toString());
|
|
1886
|
-
return `${getFixUrl({
|
|
1887
|
-
appBaseUrl,
|
|
1888
|
-
fixId,
|
|
1889
|
-
projectId,
|
|
1890
|
-
organizationId,
|
|
1891
|
-
analysisId
|
|
1892
|
-
})}?${searchParams.toString()}`;
|
|
1893
|
-
}
|
|
1894
|
-
function getFixUrl({
|
|
1895
|
-
appBaseUrl,
|
|
1896
|
-
fixId,
|
|
1897
|
-
projectId,
|
|
1898
|
-
organizationId,
|
|
1899
|
-
analysisId
|
|
1900
|
-
}) {
|
|
1901
|
-
return `${appBaseUrl}/organization/${organizationId}/project/${projectId}/report/${analysisId}/fix/${fixId}`;
|
|
1902
|
-
}
|
|
1903
|
-
function getCommitUrl(params) {
|
|
1904
|
-
const {
|
|
1905
|
-
fixId,
|
|
1906
|
-
projectId,
|
|
1907
|
-
organizationId,
|
|
1908
|
-
analysisId,
|
|
1909
|
-
redirectUrl,
|
|
1910
|
-
appBaseUrl,
|
|
1911
|
-
commentId
|
|
1912
|
-
} = params;
|
|
1913
|
-
const searchParams = new URLSearchParams();
|
|
1914
|
-
searchParams.append("redirect_url", redirectUrl);
|
|
1915
|
-
searchParams.append("comment_id", commentId.toString());
|
|
1916
|
-
return `${getFixUrl({
|
|
1917
|
-
appBaseUrl,
|
|
1918
|
-
fixId,
|
|
1919
|
-
projectId,
|
|
1920
|
-
organizationId,
|
|
1921
|
-
analysisId
|
|
1922
|
-
})}/commit?${searchParams.toString()}`;
|
|
1923
|
-
}
|
|
1924
|
-
var userNamePattern = /^(https?:\/\/)([^@]+@)?([^/]+\/.+)$/;
|
|
1925
|
-
var sshPattern = /^git@([\w.-]+):([\w./-]+)$/;
|
|
1926
|
-
function normalizeUrl(repoUrl) {
|
|
1927
|
-
let trimmedUrl = repoUrl.trim().replace(/\/+$/, "");
|
|
1928
|
-
if (repoUrl.endsWith(".git")) {
|
|
1929
|
-
trimmedUrl = trimmedUrl.slice(0, -".git".length);
|
|
1930
|
-
}
|
|
1931
|
-
const usernameMatch = trimmedUrl.match(userNamePattern);
|
|
1932
|
-
if (usernameMatch) {
|
|
1933
|
-
const [_all, protocol, _username, repoPath] = usernameMatch;
|
|
1934
|
-
trimmedUrl = `${protocol}${repoPath}`;
|
|
1935
|
-
}
|
|
1936
|
-
const sshMatch = trimmedUrl.match(sshPattern);
|
|
1937
|
-
if (sshMatch) {
|
|
1938
|
-
const [_all, hostname, reporPath] = sshMatch;
|
|
1939
|
-
trimmedUrl = `https://${hostname}/${reporPath}`;
|
|
1940
|
-
}
|
|
1941
|
-
return trimmedUrl;
|
|
1942
|
-
}
|
|
1943
|
-
var isUrlHasPath = (url) => {
|
|
1944
|
-
return new URL(url).origin !== url;
|
|
1945
|
-
};
|
|
1946
|
-
function shouldValidateUrl(repoUrl) {
|
|
1947
|
-
return repoUrl && isUrlHasPath(repoUrl);
|
|
1948
|
-
}
|
|
1949
|
-
|
|
1950
1764
|
// src/features/analysis/scm/gitlab/types.ts
|
|
1951
1765
|
import { z as z4 } from "zod";
|
|
1952
1766
|
var GitlabAuthResultZ = z4.object({
|
|
@@ -1956,7 +1770,7 @@ var GitlabAuthResultZ = z4.object({
|
|
|
1956
1770
|
});
|
|
1957
1771
|
|
|
1958
1772
|
// src/features/analysis/scm/gitlab/gitlab.ts
|
|
1959
|
-
function
|
|
1773
|
+
function removeTrailingSlash(str) {
|
|
1960
1774
|
return str.trim().replace(/\/+$/, "");
|
|
1961
1775
|
}
|
|
1962
1776
|
function getGitBeaker(options) {
|
|
@@ -2185,7 +1999,7 @@ async function getGitlabReferenceData({ ref, gitlabUrl }, options) {
|
|
|
2185
1999
|
throw new RefNotFoundError(`ref: ${ref} does not exist`);
|
|
2186
2000
|
}
|
|
2187
2001
|
function parseGitlabOwnerAndRepo(gitlabUrl) {
|
|
2188
|
-
gitlabUrl =
|
|
2002
|
+
gitlabUrl = removeTrailingSlash(gitlabUrl);
|
|
2189
2003
|
const parsingResult = parseScmURL(gitlabUrl, "GitLab" /* GitLab */);
|
|
2190
2004
|
if (!parsingResult || !parsingResult.repoName) {
|
|
2191
2005
|
throw new InvalidUrlPatternError(`invalid gitlab repo Url ${gitlabUrl}`);
|
|
@@ -2263,7 +2077,8 @@ var BaseSubmitToScmMessageZ = z5.object({
|
|
|
2263
2077
|
})
|
|
2264
2078
|
),
|
|
2265
2079
|
commitHash: z5.string(),
|
|
2266
|
-
repoUrl: z5.string()
|
|
2080
|
+
repoUrl: z5.string(),
|
|
2081
|
+
extraHeaders: z5.record(z5.string(), z5.string()).default({})
|
|
2267
2082
|
});
|
|
2268
2083
|
var submitToScmMessageType = {
|
|
2269
2084
|
commitToSameBranch: "commitToSameBranch",
|
|
@@ -2532,7 +2347,8 @@ var SCMLib = class {
|
|
|
2532
2347
|
}
|
|
2533
2348
|
const scmLibType = this.getScmLibType();
|
|
2534
2349
|
if (scmLibType === "ADO" /* ADO */) {
|
|
2535
|
-
|
|
2350
|
+
const { host, protocol, pathname } = new URL(trimmedUrl);
|
|
2351
|
+
return `${protocol}//${accessToken}@${host}${pathname}`;
|
|
2536
2352
|
}
|
|
2537
2353
|
if (this instanceof BitbucketSCMLib) {
|
|
2538
2354
|
const authData = this.getAuthData();
|
|
@@ -2580,7 +2396,7 @@ var SCMLib = class {
|
|
|
2580
2396
|
}
|
|
2581
2397
|
return this.url.split("/").at(-1) || "";
|
|
2582
2398
|
}
|
|
2583
|
-
|
|
2399
|
+
_validateAccessToken() {
|
|
2584
2400
|
if (!this.accessToken) {
|
|
2585
2401
|
console.error("no access token");
|
|
2586
2402
|
throw new Error("no access token");
|
|
@@ -2626,14 +2442,12 @@ var SCMLib = class {
|
|
|
2626
2442
|
scmLibScmTypeToScmType[z7.nativeEnum(ScmLibScmType).parse(scmType)]
|
|
2627
2443
|
);
|
|
2628
2444
|
}
|
|
2445
|
+
console.error(`error validating scm: ${scmType} `, e);
|
|
2629
2446
|
}
|
|
2630
2447
|
return new StubSCMLib(trimmedUrl, void 0, void 0);
|
|
2631
2448
|
}
|
|
2632
2449
|
_validateAccessTokenAndUrl() {
|
|
2633
|
-
|
|
2634
|
-
console.error("no access token");
|
|
2635
|
-
throw new InvalidAccessTokenError("no access token");
|
|
2636
|
-
}
|
|
2450
|
+
this._validateAccessToken();
|
|
2637
2451
|
this._validateUrl();
|
|
2638
2452
|
}
|
|
2639
2453
|
_validateUrl() {
|
|
@@ -2643,45 +2457,65 @@ var SCMLib = class {
|
|
|
2643
2457
|
}
|
|
2644
2458
|
}
|
|
2645
2459
|
};
|
|
2460
|
+
async function initAdoSdk(params) {
|
|
2461
|
+
const { url, accessToken, scmOrg } = params;
|
|
2462
|
+
const adoClientParams = await getAdoClientParams({
|
|
2463
|
+
tokenOrg: scmOrg,
|
|
2464
|
+
accessToken,
|
|
2465
|
+
url
|
|
2466
|
+
});
|
|
2467
|
+
return getAdoSdk(adoClientParams);
|
|
2468
|
+
}
|
|
2646
2469
|
var AdoSCMLib = class extends SCMLib {
|
|
2470
|
+
constructor(url, accessToken, scmOrg) {
|
|
2471
|
+
super(url, accessToken, scmOrg);
|
|
2472
|
+
__publicField(this, "_adoSdkPromise");
|
|
2473
|
+
this._adoSdkPromise = initAdoSdk({ accessToken, url, scmOrg });
|
|
2474
|
+
}
|
|
2475
|
+
async getAdoSdk() {
|
|
2476
|
+
if (!this._adoSdkPromise) {
|
|
2477
|
+
console.error("ado sdk was not initialized");
|
|
2478
|
+
throw new InvalidAccessTokenError("ado sdk was not initialized");
|
|
2479
|
+
}
|
|
2480
|
+
return this._adoSdkPromise;
|
|
2481
|
+
}
|
|
2647
2482
|
async createSubmitRequest(params) {
|
|
2648
2483
|
this._validateAccessTokenAndUrl();
|
|
2649
2484
|
const { targetBranchName, sourceBranchName, title, body } = params;
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
})
|
|
2660
|
-
);
|
|
2485
|
+
const adoSdk = await this.getAdoSdk();
|
|
2486
|
+
const pullRequestId = await adoSdk.createAdoPullRequest({
|
|
2487
|
+
title,
|
|
2488
|
+
body,
|
|
2489
|
+
targetBranchName,
|
|
2490
|
+
sourceBranchName,
|
|
2491
|
+
repoUrl: this.url
|
|
2492
|
+
});
|
|
2493
|
+
return String(pullRequestId);
|
|
2661
2494
|
}
|
|
2662
2495
|
async validateParams() {
|
|
2663
|
-
return
|
|
2496
|
+
return adoValidateParams({
|
|
2664
2497
|
url: this.url,
|
|
2665
2498
|
accessToken: this.accessToken,
|
|
2666
2499
|
tokenOrg: this.scmOrg
|
|
2667
2500
|
});
|
|
2668
2501
|
}
|
|
2669
2502
|
async getRepoList(scmOrg) {
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
throw new Error(
|
|
2503
|
+
this._validateAccessToken();
|
|
2504
|
+
if (this.url && new URL(this.url).origin !== scmCloudUrl.Ado) {
|
|
2505
|
+
throw new Error(
|
|
2506
|
+
`Oauth token is not supported for ADO on prem - ${origin} `
|
|
2507
|
+
);
|
|
2673
2508
|
}
|
|
2674
|
-
return
|
|
2509
|
+
return getAdoRepoList({
|
|
2675
2510
|
orgName: scmOrg,
|
|
2676
|
-
|
|
2677
|
-
|
|
2511
|
+
accessToken: this.accessToken,
|
|
2512
|
+
tokenOrg: this.scmOrg
|
|
2678
2513
|
});
|
|
2679
2514
|
}
|
|
2680
2515
|
async getBranchList() {
|
|
2681
2516
|
this._validateAccessTokenAndUrl();
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
tokenOrg: this.scmOrg,
|
|
2517
|
+
const adoSdk = await this.getAdoSdk();
|
|
2518
|
+
return adoSdk.getAdoBranchList({
|
|
2685
2519
|
repoUrl: this.url
|
|
2686
2520
|
});
|
|
2687
2521
|
}
|
|
@@ -2690,7 +2524,7 @@ var AdoSCMLib = class extends SCMLib {
|
|
|
2690
2524
|
}
|
|
2691
2525
|
getAuthHeaders() {
|
|
2692
2526
|
if (this.accessToken) {
|
|
2693
|
-
if (
|
|
2527
|
+
if (getAdoTokenInfo(this.accessToken).type === "OAUTH") {
|
|
2694
2528
|
return {
|
|
2695
2529
|
authorization: `Bearer ${this.accessToken}`
|
|
2696
2530
|
};
|
|
@@ -2704,29 +2538,26 @@ var AdoSCMLib = class extends SCMLib {
|
|
|
2704
2538
|
}
|
|
2705
2539
|
return {};
|
|
2706
2540
|
}
|
|
2707
|
-
getDownloadUrl(sha) {
|
|
2541
|
+
async getDownloadUrl(sha) {
|
|
2708
2542
|
this._validateUrl();
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
);
|
|
2543
|
+
const adoSdk = await this.getAdoSdk();
|
|
2544
|
+
return adoSdk.getAdoDownloadUrl({ repoUrl: this.url, branch: sha });
|
|
2712
2545
|
}
|
|
2713
2546
|
async _getUsernameForAuthUrl() {
|
|
2714
2547
|
throw new Error("_getUsernameForAuthUrl() is not relevant for ADO");
|
|
2715
2548
|
}
|
|
2716
2549
|
async getIsRemoteBranch(branch) {
|
|
2717
2550
|
this._validateAccessTokenAndUrl();
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
tokenOrg: this.scmOrg,
|
|
2551
|
+
const adoSdk = await this.getAdoSdk();
|
|
2552
|
+
return adoSdk.getAdoIsRemoteBranch({
|
|
2721
2553
|
repoUrl: this.url,
|
|
2722
2554
|
branch
|
|
2723
2555
|
});
|
|
2724
2556
|
}
|
|
2725
2557
|
async getUserHasAccessToRepo() {
|
|
2726
2558
|
this._validateAccessTokenAndUrl();
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
tokenOrg: this.scmOrg,
|
|
2559
|
+
const adoSdk = await this.getAdoSdk();
|
|
2560
|
+
return adoSdk.getAdoIsUserCollaborator({
|
|
2730
2561
|
repoUrl: this.url
|
|
2731
2562
|
});
|
|
2732
2563
|
}
|
|
@@ -2735,46 +2566,48 @@ var AdoSCMLib = class extends SCMLib {
|
|
|
2735
2566
|
}
|
|
2736
2567
|
async getSubmitRequestStatus(scmSubmitRequestId) {
|
|
2737
2568
|
this._validateAccessTokenAndUrl();
|
|
2738
|
-
const
|
|
2739
|
-
|
|
2740
|
-
tokenOrg: this.scmOrg,
|
|
2569
|
+
const adoSdk = await this.getAdoSdk();
|
|
2570
|
+
const state = await adoSdk.getAdoPullRequestStatus({
|
|
2741
2571
|
repoUrl: this.url,
|
|
2742
2572
|
prNumber: Number(scmSubmitRequestId)
|
|
2743
2573
|
});
|
|
2744
2574
|
switch (state) {
|
|
2745
|
-
case
|
|
2575
|
+
case 3 /* Completed */:
|
|
2746
2576
|
return "merged";
|
|
2747
|
-
case
|
|
2577
|
+
case 1 /* Active */:
|
|
2748
2578
|
return "open";
|
|
2749
|
-
case
|
|
2579
|
+
case 2 /* Abandoned */:
|
|
2750
2580
|
return "closed";
|
|
2751
2581
|
default:
|
|
2752
2582
|
throw new Error(`unknown state ${state}`);
|
|
2753
2583
|
}
|
|
2754
2584
|
}
|
|
2755
2585
|
async getRepoBlameRanges(_ref, _path) {
|
|
2756
|
-
|
|
2586
|
+
const adoSdk = await this.getAdoSdk();
|
|
2587
|
+
return await adoSdk.getAdoBlameRanges();
|
|
2757
2588
|
}
|
|
2758
2589
|
async getReferenceData(ref) {
|
|
2759
2590
|
this._validateUrl();
|
|
2760
|
-
|
|
2591
|
+
const adoSdk = await this.getAdoSdk();
|
|
2592
|
+
return await adoSdk.getAdoReferenceData({
|
|
2761
2593
|
ref,
|
|
2762
|
-
repoUrl: this.url
|
|
2763
|
-
accessToken: this.accessToken,
|
|
2764
|
-
tokenOrg: this.scmOrg
|
|
2594
|
+
repoUrl: this.url
|
|
2765
2595
|
});
|
|
2766
2596
|
}
|
|
2767
2597
|
async getRepoDefaultBranch() {
|
|
2768
2598
|
this._validateUrl();
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
accessToken: this.accessToken
|
|
2599
|
+
const adoSdk = await this.getAdoSdk();
|
|
2600
|
+
return await adoSdk.getAdoRepoDefaultBranch({
|
|
2601
|
+
repoUrl: this.url
|
|
2773
2602
|
});
|
|
2774
2603
|
}
|
|
2775
|
-
getPrUrl(prNumber) {
|
|
2776
|
-
this.
|
|
2777
|
-
|
|
2604
|
+
async getPrUrl(prNumber) {
|
|
2605
|
+
this._validateUrl();
|
|
2606
|
+
const adoSdk = await this.getAdoSdk();
|
|
2607
|
+
return adoSdk.getAdoPrUrl({
|
|
2608
|
+
url: this.url,
|
|
2609
|
+
prNumber
|
|
2610
|
+
});
|
|
2778
2611
|
}
|
|
2779
2612
|
};
|
|
2780
2613
|
var GitlabSCMLib = class extends SCMLib {
|
|
@@ -2937,7 +2770,7 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
2937
2770
|
return String(pullRequestResult.data.number);
|
|
2938
2771
|
}
|
|
2939
2772
|
async forkRepo(repoUrl) {
|
|
2940
|
-
this.
|
|
2773
|
+
this._validateAccessToken();
|
|
2941
2774
|
return this.githubSdk.forkRepo({
|
|
2942
2775
|
repoUrl
|
|
2943
2776
|
});
|
|
@@ -3017,7 +2850,7 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
3017
2850
|
return z7.string().parse(prRes.data);
|
|
3018
2851
|
}
|
|
3019
2852
|
async getRepoList(_scmOrg) {
|
|
3020
|
-
this.
|
|
2853
|
+
this._validateAccessToken();
|
|
3021
2854
|
return this.githubSdk.getGithubRepoList();
|
|
3022
2855
|
}
|
|
3023
2856
|
async getBranchList() {
|
|
@@ -3060,7 +2893,7 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
3060
2893
|
});
|
|
3061
2894
|
}
|
|
3062
2895
|
async getUsername() {
|
|
3063
|
-
this.
|
|
2896
|
+
this._validateAccessToken();
|
|
3064
2897
|
return this.githubSdk.getGithubUsername();
|
|
3065
2898
|
}
|
|
3066
2899
|
async getSubmitRequestStatus(scmSubmitRequestId) {
|
|
@@ -3236,7 +3069,7 @@ var BitbucketSCMLib = class extends SCMLib {
|
|
|
3236
3069
|
const authType = this.bitbucketSdk.getAuthType();
|
|
3237
3070
|
switch (authType) {
|
|
3238
3071
|
case "basic": {
|
|
3239
|
-
this.
|
|
3072
|
+
this._validateAccessToken();
|
|
3240
3073
|
const { username, password } = getUserAndPassword(this.accessToken);
|
|
3241
3074
|
return { username, password, authType };
|
|
3242
3075
|
}
|
|
@@ -3262,7 +3095,7 @@ var BitbucketSCMLib = class extends SCMLib {
|
|
|
3262
3095
|
});
|
|
3263
3096
|
}
|
|
3264
3097
|
async getRepoList(scmOrg) {
|
|
3265
|
-
this.
|
|
3098
|
+
this._validateAccessToken();
|
|
3266
3099
|
return this.bitbucketSdk.getRepos({
|
|
3267
3100
|
workspaceSlug: scmOrg
|
|
3268
3101
|
});
|
|
@@ -3284,7 +3117,7 @@ var BitbucketSCMLib = class extends SCMLib {
|
|
|
3284
3117
|
case "token":
|
|
3285
3118
|
return { authorization: `Bearer ${this.accessToken}` };
|
|
3286
3119
|
case "basic": {
|
|
3287
|
-
this.
|
|
3120
|
+
this._validateAccessToken();
|
|
3288
3121
|
const { username, password } = getUserAndPassword(this.accessToken);
|
|
3289
3122
|
return {
|
|
3290
3123
|
authorization: `Basic ${Buffer.from(
|
|
@@ -3323,7 +3156,7 @@ var BitbucketSCMLib = class extends SCMLib {
|
|
|
3323
3156
|
return this.bitbucketSdk.getIsUserCollaborator({ repoUrl: this.url });
|
|
3324
3157
|
}
|
|
3325
3158
|
async getUsername() {
|
|
3326
|
-
this.
|
|
3159
|
+
this._validateAccessToken();
|
|
3327
3160
|
const res = await this.bitbucketSdk.getUser();
|
|
3328
3161
|
return z7.string().parse(res.username);
|
|
3329
3162
|
}
|
|
@@ -3375,309 +3208,516 @@ var BitbucketSCMLib = class extends SCMLib {
|
|
|
3375
3208
|
}
|
|
3376
3209
|
};
|
|
3377
3210
|
|
|
3378
|
-
// src/features/analysis/scm/
|
|
3379
|
-
|
|
3380
|
-
var
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3211
|
+
// src/features/analysis/scm/ado/validation.ts
|
|
3212
|
+
import { z as z8 } from "zod";
|
|
3213
|
+
var ValidPullRequestStatusZ = z8.union([
|
|
3214
|
+
z8.literal(1 /* Active */),
|
|
3215
|
+
z8.literal(2 /* Abandoned */),
|
|
3216
|
+
z8.literal(3 /* Completed */)
|
|
3217
|
+
]);
|
|
3218
|
+
var AdoAuthResultZ = z8.object({
|
|
3219
|
+
access_token: z8.string().min(1),
|
|
3220
|
+
token_type: z8.string().min(1),
|
|
3221
|
+
refresh_token: z8.string().min(1)
|
|
3389
3222
|
});
|
|
3390
|
-
var
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3223
|
+
var profileZ = z8.object({
|
|
3224
|
+
displayName: z8.string(),
|
|
3225
|
+
publicAlias: z8.string().min(1),
|
|
3226
|
+
emailAddress: z8.string(),
|
|
3227
|
+
coreRevision: z8.number(),
|
|
3228
|
+
timeStamp: z8.string(),
|
|
3229
|
+
id: z8.string(),
|
|
3230
|
+
revision: z8.number()
|
|
3395
3231
|
});
|
|
3396
|
-
var
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3232
|
+
var accountsZ = z8.object({
|
|
3233
|
+
count: z8.number(),
|
|
3234
|
+
value: z8.array(
|
|
3235
|
+
z8.object({
|
|
3236
|
+
accountId: z8.string(),
|
|
3237
|
+
accountUri: z8.string(),
|
|
3238
|
+
accountName: z8.string()
|
|
3239
|
+
})
|
|
3240
|
+
)
|
|
3400
3241
|
});
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3242
|
+
|
|
3243
|
+
// src/features/analysis/scm/ado/utils.ts
|
|
3244
|
+
function _getPublicAdoClient({
|
|
3245
|
+
orgName,
|
|
3246
|
+
origin: origin2
|
|
3247
|
+
}) {
|
|
3248
|
+
const orgUrl = `${origin2}/${orgName}`;
|
|
3249
|
+
const authHandler = api.getPersonalAccessTokenHandler("");
|
|
3250
|
+
authHandler.canHandleAuthentication = () => false;
|
|
3251
|
+
authHandler.prepareRequest = (_options) => {
|
|
3252
|
+
return;
|
|
3408
3253
|
};
|
|
3254
|
+
const connection = new api.WebApi(orgUrl, authHandler);
|
|
3255
|
+
return connection;
|
|
3409
3256
|
}
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
const res = await fetch(BITBUCKET_ACCESS_TOKEN_URL, {
|
|
3413
|
-
method: "POST",
|
|
3414
|
-
headers: {
|
|
3415
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
3416
|
-
Authorization: "Basic " + btoa(`${bitbucketClientId}:${bitbucketClientSecret}`)
|
|
3417
|
-
},
|
|
3418
|
-
body: querystring3.stringify(
|
|
3419
|
-
authType === "refresh_token" ? {
|
|
3420
|
-
grant_type: authType,
|
|
3421
|
-
refresh_token: params.refreshToken
|
|
3422
|
-
} : {
|
|
3423
|
-
grant_type: authType,
|
|
3424
|
-
code: params.code
|
|
3425
|
-
}
|
|
3426
|
-
)
|
|
3427
|
-
});
|
|
3428
|
-
const authResult = await res.json();
|
|
3429
|
-
return BitbucketAuthResultZ.parse(authResult);
|
|
3257
|
+
function removeTrailingSlash2(str) {
|
|
3258
|
+
return str.trim().replace(/\/+$/, "");
|
|
3430
3259
|
}
|
|
3431
|
-
function
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
case "basic":
|
|
3438
|
-
return new Bitbucket({
|
|
3439
|
-
auth: {
|
|
3440
|
-
password: params.password,
|
|
3441
|
-
username: params.username
|
|
3442
|
-
}
|
|
3443
|
-
});
|
|
3260
|
+
function parseAdoOwnerAndRepo(adoUrl) {
|
|
3261
|
+
adoUrl = removeTrailingSlash2(adoUrl);
|
|
3262
|
+
const parsingResult = parseScmURL(adoUrl, "Ado" /* Ado */);
|
|
3263
|
+
if (!parsingResult) {
|
|
3264
|
+
throw new InvalidUrlPatternError(`
|
|
3265
|
+
: ${adoUrl}`);
|
|
3444
3266
|
}
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3267
|
+
const {
|
|
3268
|
+
organization,
|
|
3269
|
+
repoName,
|
|
3270
|
+
projectName,
|
|
3271
|
+
projectPath,
|
|
3272
|
+
pathElements,
|
|
3273
|
+
hostname,
|
|
3274
|
+
protocol
|
|
3275
|
+
} = parsingResult;
|
|
3448
3276
|
return {
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
});
|
|
3474
|
-
if (!res.data.values) {
|
|
3475
|
-
return [];
|
|
3476
|
-
}
|
|
3477
|
-
return res.data.values.filter((branch) => !!branch.name).map((branch) => z8.string().parse(branch.name));
|
|
3478
|
-
},
|
|
3479
|
-
async getIsUserCollaborator(params2) {
|
|
3480
|
-
const { repoUrl } = params2;
|
|
3481
|
-
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(repoUrl);
|
|
3482
|
-
const fullRepoName = `${workspace}/${repoSlug}`;
|
|
3483
|
-
const res = await bitbucketClient.user.listPermissionsForRepos({
|
|
3484
|
-
q: `repository.full_name~"${fullRepoName}"`
|
|
3485
|
-
});
|
|
3486
|
-
return res.data.values?.some(
|
|
3487
|
-
(res2) => res2.repository?.full_name === fullRepoName
|
|
3488
|
-
) ?? false;
|
|
3489
|
-
},
|
|
3490
|
-
async createPullRequest(params2) {
|
|
3491
|
-
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
3492
|
-
params2.repoUrl
|
|
3493
|
-
);
|
|
3494
|
-
const res = await bitbucketClient.pullrequests.create({
|
|
3495
|
-
repo_slug: repoSlug,
|
|
3496
|
-
workspace,
|
|
3497
|
-
_body: {
|
|
3498
|
-
type: "pullrequest",
|
|
3499
|
-
title: params2.title,
|
|
3500
|
-
summary: {
|
|
3501
|
-
raw: params2.body
|
|
3502
|
-
},
|
|
3503
|
-
source: {
|
|
3504
|
-
branch: {
|
|
3505
|
-
name: params2.sourceBranchName
|
|
3506
|
-
}
|
|
3507
|
-
},
|
|
3508
|
-
destination: {
|
|
3509
|
-
branch: {
|
|
3510
|
-
name: params2.targetBranchName
|
|
3511
|
-
}
|
|
3512
|
-
}
|
|
3513
|
-
}
|
|
3514
|
-
});
|
|
3515
|
-
return res.data;
|
|
3516
|
-
},
|
|
3517
|
-
async getDownloadlink(params2) {
|
|
3518
|
-
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
3519
|
-
params2.repoUrl
|
|
3520
|
-
);
|
|
3521
|
-
const res = await bitbucketClient.downloads.list({
|
|
3522
|
-
repo_slug: repoSlug,
|
|
3523
|
-
workspace
|
|
3524
|
-
});
|
|
3525
|
-
return res.data;
|
|
3526
|
-
},
|
|
3527
|
-
async getBranch(params2) {
|
|
3528
|
-
const { repoSlug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
3529
|
-
params2.repoUrl
|
|
3530
|
-
);
|
|
3531
|
-
const res = await bitbucketClient.refs.getBranch({
|
|
3532
|
-
name: params2.branchName,
|
|
3533
|
-
repo_slug: repoSlug,
|
|
3534
|
-
workspace
|
|
3277
|
+
owner: decodeURI(organization),
|
|
3278
|
+
repo: decodeURI(repoName),
|
|
3279
|
+
projectName: projectName ? decodeURI(projectName) : void 0,
|
|
3280
|
+
projectPath,
|
|
3281
|
+
pathElements,
|
|
3282
|
+
origin: `${protocol}//${hostname}`
|
|
3283
|
+
};
|
|
3284
|
+
}
|
|
3285
|
+
async function getAdoConnectData({
|
|
3286
|
+
url,
|
|
3287
|
+
tokenOrg,
|
|
3288
|
+
adoTokenInfo
|
|
3289
|
+
}) {
|
|
3290
|
+
if (url && new URL(url).origin !== url) {
|
|
3291
|
+
const { owner, origin: origin2 } = parseAdoOwnerAndRepo(url);
|
|
3292
|
+
return {
|
|
3293
|
+
org: owner,
|
|
3294
|
+
origin: origin2
|
|
3295
|
+
};
|
|
3296
|
+
}
|
|
3297
|
+
if (!tokenOrg) {
|
|
3298
|
+
if (adoTokenInfo.type === "OAUTH" /* OAUTH */) {
|
|
3299
|
+
const [org] = await _getOrgsForOauthToken({
|
|
3300
|
+
oauthToken: adoTokenInfo.accessToken
|
|
3535
3301
|
});
|
|
3536
|
-
return
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3302
|
+
return {
|
|
3303
|
+
org: z9.string().parse(org),
|
|
3304
|
+
origin: DEFUALT_ADO_ORIGIN
|
|
3305
|
+
};
|
|
3306
|
+
}
|
|
3307
|
+
throw new InvalidRepoUrlError("ADO URL is null");
|
|
3308
|
+
}
|
|
3309
|
+
return {
|
|
3310
|
+
org: tokenOrg,
|
|
3311
|
+
origin: DEFUALT_ADO_ORIGIN
|
|
3312
|
+
};
|
|
3313
|
+
}
|
|
3314
|
+
async function getAdoApiClient(params) {
|
|
3315
|
+
const { origin: origin2 = DEFUALT_ADO_ORIGIN, orgName } = params;
|
|
3316
|
+
if (params.tokenType === "NONE" /* NONE */ || // move to public client if the token is not associated with the PAT org
|
|
3317
|
+
params.tokenType === "PAT" /* PAT */ && params.patTokenOrg !== orgName) {
|
|
3318
|
+
return _getPublicAdoClient({ orgName, origin: origin2 });
|
|
3319
|
+
}
|
|
3320
|
+
const orgUrl = `${origin2}/${orgName}`;
|
|
3321
|
+
if (params.tokenType === "OAUTH" /* OAUTH */) {
|
|
3322
|
+
if (origin2 !== DEFUALT_ADO_ORIGIN) {
|
|
3323
|
+
throw new Error(
|
|
3324
|
+
`Oauth token is not supported for ADO on prem - ${origin2} `
|
|
3541
3325
|
);
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3326
|
+
}
|
|
3327
|
+
const connection2 = new api.WebApi(
|
|
3328
|
+
orgUrl,
|
|
3329
|
+
api.getBearerHandler(params.accessToken),
|
|
3330
|
+
{}
|
|
3331
|
+
);
|
|
3332
|
+
return connection2;
|
|
3333
|
+
}
|
|
3334
|
+
const authHandler = api.getPersonalAccessTokenHandler(params.accessToken);
|
|
3335
|
+
const isBroker = BROKERED_HOSTS.includes(new URL(orgUrl).origin);
|
|
3336
|
+
const connection = new api.WebApi(
|
|
3337
|
+
orgUrl,
|
|
3338
|
+
authHandler,
|
|
3339
|
+
isBroker ? {
|
|
3340
|
+
proxy: {
|
|
3341
|
+
proxyUrl: GIT_PROXY_HOST
|
|
3342
|
+
},
|
|
3343
|
+
ignoreSslError: true
|
|
3344
|
+
} : void 0
|
|
3345
|
+
);
|
|
3346
|
+
return connection;
|
|
3347
|
+
}
|
|
3348
|
+
function getAdoTokenInfo(token) {
|
|
3349
|
+
if (!token) {
|
|
3350
|
+
return { type: "NONE" /* NONE */ };
|
|
3351
|
+
}
|
|
3352
|
+
if (token.includes(".")) {
|
|
3353
|
+
return { type: "OAUTH" /* OAUTH */, accessToken: token };
|
|
3354
|
+
}
|
|
3355
|
+
return { type: "PAT" /* PAT */, accessToken: token };
|
|
3356
|
+
}
|
|
3357
|
+
async function getAdoClientParams(params) {
|
|
3358
|
+
const { url, accessToken, tokenOrg } = params;
|
|
3359
|
+
const adoTokenInfo = getAdoTokenInfo(accessToken);
|
|
3360
|
+
const { org, origin: origin2 } = await getAdoConnectData({
|
|
3361
|
+
url,
|
|
3362
|
+
tokenOrg,
|
|
3363
|
+
adoTokenInfo
|
|
3364
|
+
});
|
|
3365
|
+
switch (adoTokenInfo.type) {
|
|
3366
|
+
case "NONE" /* NONE */:
|
|
3367
|
+
return {
|
|
3368
|
+
tokenType: "NONE" /* NONE */,
|
|
3369
|
+
origin: origin2,
|
|
3370
|
+
orgName: org.toLowerCase()
|
|
3371
|
+
};
|
|
3372
|
+
case "OAUTH" /* OAUTH */: {
|
|
3373
|
+
return {
|
|
3374
|
+
tokenType: "OAUTH" /* OAUTH */,
|
|
3375
|
+
accessToken: adoTokenInfo.accessToken,
|
|
3376
|
+
origin: origin2,
|
|
3377
|
+
orgName: org.toLowerCase()
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
case "PAT" /* PAT */: {
|
|
3381
|
+
return {
|
|
3382
|
+
tokenType: "PAT" /* PAT */,
|
|
3383
|
+
accessToken: adoTokenInfo.accessToken,
|
|
3384
|
+
patTokenOrg: z9.string().parse(tokenOrg).toLowerCase(),
|
|
3385
|
+
origin: origin2,
|
|
3386
|
+
orgName: org.toLowerCase()
|
|
3387
|
+
};
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
async function adoValidateParams({
|
|
3392
|
+
url,
|
|
3393
|
+
accessToken,
|
|
3394
|
+
tokenOrg
|
|
3395
|
+
}) {
|
|
3396
|
+
try {
|
|
3397
|
+
const api2 = await getAdoApiClient(
|
|
3398
|
+
await getAdoClientParams({ url, accessToken, tokenOrg })
|
|
3399
|
+
);
|
|
3400
|
+
await api2.connect();
|
|
3401
|
+
} catch (e) {
|
|
3402
|
+
console.log("adoValidateParams error", e);
|
|
3403
|
+
const error = e;
|
|
3404
|
+
const code = error.code || error.status || error.statusCode || error.response?.status || error.response?.statusCode || error.response?.code;
|
|
3405
|
+
const description = error.description || `${e}`;
|
|
3406
|
+
if (code === 401 || code === 403 || description.includes("401") || description.includes("403")) {
|
|
3407
|
+
throw new InvalidAccessTokenError(`invalid ADO access token`);
|
|
3408
|
+
}
|
|
3409
|
+
if (code === 404 || description.includes("404") || description.includes("Not Found")) {
|
|
3410
|
+
throw new InvalidRepoUrlError(`invalid ADO repo URL ${url}`);
|
|
3411
|
+
}
|
|
3412
|
+
throw e;
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
async function _getOrgsForOauthToken({
|
|
3416
|
+
oauthToken
|
|
3417
|
+
}) {
|
|
3418
|
+
const profileRes = await fetch(
|
|
3419
|
+
"https://app.vssps.visualstudio.com/_apis/profile/profiles/me?api-version=6.0",
|
|
3420
|
+
{
|
|
3421
|
+
method: "GET",
|
|
3422
|
+
headers: {
|
|
3423
|
+
Authorization: `Bearer ${oauthToken}`
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
);
|
|
3427
|
+
const profileJson = await profileRes.json();
|
|
3428
|
+
const profile = profileZ.parse(profileJson);
|
|
3429
|
+
const accountsRes = await fetch(
|
|
3430
|
+
`https://app.vssps.visualstudio.com/_apis/accounts?memberId=${profile.publicAlias}&api-version=6.0`,
|
|
3431
|
+
{
|
|
3432
|
+
method: "GET",
|
|
3433
|
+
headers: {
|
|
3434
|
+
Authorization: `Bearer ${oauthToken}`
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
);
|
|
3438
|
+
const accountsJson = await accountsRes.json();
|
|
3439
|
+
const accounts = accountsZ.parse(accountsJson);
|
|
3440
|
+
const orgs = accounts.value.map((account) => account.accountName).filter((value, index, array) => array.indexOf(value) === index);
|
|
3441
|
+
return orgs;
|
|
3442
|
+
}
|
|
3443
|
+
|
|
3444
|
+
// src/features/analysis/scm/ado/ado.ts
|
|
3445
|
+
async function getAdoSdk(params) {
|
|
3446
|
+
const api2 = await getAdoApiClient(params);
|
|
3447
|
+
return {
|
|
3448
|
+
async getAdoIsUserCollaborator({ repoUrl }) {
|
|
3449
|
+
try {
|
|
3450
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3451
|
+
const git = await api2.getGitApi();
|
|
3452
|
+
const branches = await git.getBranches(repo, projectName);
|
|
3453
|
+
if (!branches || branches.length === 0) {
|
|
3454
|
+
throw new InvalidRepoUrlError("no branches");
|
|
3455
|
+
}
|
|
3456
|
+
return true;
|
|
3457
|
+
} catch (e) {
|
|
3458
|
+
return false;
|
|
3459
|
+
}
|
|
3547
3460
|
},
|
|
3548
|
-
async
|
|
3549
|
-
|
|
3550
|
-
|
|
3461
|
+
async getAdoPullRequestStatus({
|
|
3462
|
+
repoUrl,
|
|
3463
|
+
prNumber
|
|
3464
|
+
}) {
|
|
3465
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3466
|
+
const git = await api2.getGitApi();
|
|
3467
|
+
const res = await git.getPullRequest(repo, prNumber, projectName);
|
|
3468
|
+
const parsedPullRequestStatus = ValidPullRequestStatusZ.safeParse(
|
|
3469
|
+
res.status
|
|
3551
3470
|
);
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
});
|
|
3557
|
-
return res.data;
|
|
3558
|
-
},
|
|
3559
|
-
async getUser() {
|
|
3560
|
-
const res = await bitbucketClient.user.get({});
|
|
3561
|
-
return res.data;
|
|
3471
|
+
if (!parsedPullRequestStatus.success) {
|
|
3472
|
+
throw new Error("bad pr status for ADO");
|
|
3473
|
+
}
|
|
3474
|
+
return parsedPullRequestStatus.data;
|
|
3562
3475
|
},
|
|
3563
|
-
async
|
|
3564
|
-
|
|
3565
|
-
|
|
3476
|
+
async getAdoIsRemoteBranch({
|
|
3477
|
+
repoUrl,
|
|
3478
|
+
branch
|
|
3566
3479
|
}) {
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
(promise) => promise.status === "fulfilled"
|
|
3574
|
-
);
|
|
3575
|
-
if (!refPromise) {
|
|
3576
|
-
throw new RefNotFoundError(`Invalid reference ${ref} for ${url}`);
|
|
3480
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3481
|
+
const git = await api2.getGitApi();
|
|
3482
|
+
try {
|
|
3483
|
+
const branchStatus = await git.getBranch(repo, branch, projectName);
|
|
3484
|
+
if (!branchStatus || !branchStatus.commit) {
|
|
3485
|
+
throw new InvalidRepoUrlError("no branch status");
|
|
3577
3486
|
}
|
|
3578
|
-
return
|
|
3579
|
-
})
|
|
3487
|
+
return branchStatus.name === branch;
|
|
3488
|
+
} catch (e) {
|
|
3489
|
+
return false;
|
|
3490
|
+
}
|
|
3580
3491
|
},
|
|
3581
|
-
async
|
|
3582
|
-
const {
|
|
3583
|
-
const
|
|
3584
|
-
const
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
}
|
|
3589
|
-
return GetRefererenceResultZ.parse({
|
|
3590
|
-
sha: tagRes.data.target?.hash,
|
|
3591
|
-
type: "TAG" /* TAG */,
|
|
3592
|
-
date: new Date(z8.string().parse(tagRes.data.target?.date))
|
|
3593
|
-
});
|
|
3492
|
+
async getAdoPrUrl({ url, prNumber }) {
|
|
3493
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(url);
|
|
3494
|
+
const git = await api2.getGitApi();
|
|
3495
|
+
const getRepositoryRes = await git.getRepository(
|
|
3496
|
+
decodeURI(repo),
|
|
3497
|
+
projectName ? decodeURI(projectName) : void 0
|
|
3498
|
+
);
|
|
3499
|
+
return `${getRepositoryRes.webUrl}/pullrequest/${prNumber}`;
|
|
3594
3500
|
},
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3501
|
+
getAdoDownloadUrl({
|
|
3502
|
+
repoUrl,
|
|
3503
|
+
branch
|
|
3504
|
+
}) {
|
|
3505
|
+
const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3506
|
+
const url = new URL(repoUrl);
|
|
3507
|
+
const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
|
|
3508
|
+
return `${origin2}/${owner}/${projectName}/_apis/git/repositories/${repo}/items/items?path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
|
|
3602
3509
|
},
|
|
3603
|
-
async
|
|
3604
|
-
const
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3510
|
+
async getAdoBranchList({ repoUrl }) {
|
|
3511
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3512
|
+
const git = await api2.getGitApi();
|
|
3513
|
+
try {
|
|
3514
|
+
const res = await git.getBranches(repo, projectName);
|
|
3515
|
+
res.sort((a, b) => {
|
|
3516
|
+
if (!a.commit?.committer?.date || !b.commit?.committer?.date) {
|
|
3517
|
+
return 0;
|
|
3518
|
+
}
|
|
3519
|
+
return b.commit?.committer?.date.getTime() - a.commit?.committer?.date.getTime();
|
|
3520
|
+
});
|
|
3521
|
+
return res.reduce((acc, branch) => {
|
|
3522
|
+
if (!branch.name) {
|
|
3523
|
+
return acc;
|
|
3524
|
+
}
|
|
3525
|
+
acc.push(branch.name);
|
|
3526
|
+
return acc;
|
|
3527
|
+
}, []);
|
|
3528
|
+
} catch (e) {
|
|
3529
|
+
return [];
|
|
3530
|
+
}
|
|
3610
3531
|
},
|
|
3611
|
-
async
|
|
3612
|
-
|
|
3613
|
-
const
|
|
3614
|
-
const
|
|
3615
|
-
|
|
3532
|
+
async createAdoPullRequest(options) {
|
|
3533
|
+
const { repoUrl, sourceBranchName, targetBranchName, title, body } = options;
|
|
3534
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3535
|
+
const git = await api2.getGitApi();
|
|
3536
|
+
const res = await git.createPullRequest(
|
|
3537
|
+
{
|
|
3538
|
+
sourceRefName: `refs/heads/${sourceBranchName}`,
|
|
3539
|
+
targetRefName: `refs/heads/${targetBranchName}`,
|
|
3540
|
+
title,
|
|
3541
|
+
description: body
|
|
3542
|
+
},
|
|
3543
|
+
repo,
|
|
3544
|
+
projectName
|
|
3545
|
+
);
|
|
3546
|
+
return res.pullRequestId;
|
|
3616
3547
|
},
|
|
3617
|
-
async
|
|
3618
|
-
|
|
3619
|
-
|
|
3548
|
+
async getAdoRepoDefaultBranch({
|
|
3549
|
+
repoUrl
|
|
3550
|
+
}) {
|
|
3551
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3552
|
+
const git = await api2.getGitApi();
|
|
3553
|
+
const getRepositoryRes = await git.getRepository(
|
|
3554
|
+
decodeURI(repo),
|
|
3555
|
+
projectName ? decodeURI(projectName) : void 0
|
|
3620
3556
|
);
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
await
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3557
|
+
if (!getRepositoryRes?.defaultBranch) {
|
|
3558
|
+
throw new InvalidRepoUrlError("no default branch");
|
|
3559
|
+
}
|
|
3560
|
+
return getRepositoryRes.defaultBranch.replace("refs/heads/", "");
|
|
3561
|
+
},
|
|
3562
|
+
// todo: refactor this function
|
|
3563
|
+
async getAdoReferenceData({
|
|
3564
|
+
ref,
|
|
3565
|
+
repoUrl
|
|
3566
|
+
}) {
|
|
3567
|
+
const { repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
|
|
3568
|
+
if (!projectName) {
|
|
3569
|
+
throw new InvalidUrlPatternError("no project name");
|
|
3570
|
+
}
|
|
3571
|
+
const git = await api2.getGitApi();
|
|
3572
|
+
const results = await Promise.allSettled([
|
|
3573
|
+
(async () => {
|
|
3574
|
+
const res = await git.getBranch(repo, ref, projectName);
|
|
3575
|
+
if (!res.commit || !res.commit.commitId) {
|
|
3576
|
+
throw new InvalidRepoUrlError("no commit on branch");
|
|
3577
|
+
}
|
|
3578
|
+
return {
|
|
3579
|
+
sha: res.commit.commitId,
|
|
3580
|
+
type: "BRANCH" /* BRANCH */,
|
|
3581
|
+
date: res.commit.committer?.date || /* @__PURE__ */ new Date()
|
|
3582
|
+
};
|
|
3583
|
+
})(),
|
|
3584
|
+
(async () => {
|
|
3585
|
+
const res = await git.getCommits(
|
|
3586
|
+
repo,
|
|
3587
|
+
{
|
|
3588
|
+
fromCommitId: ref,
|
|
3589
|
+
toCommitId: ref,
|
|
3590
|
+
$top: 1
|
|
3591
|
+
},
|
|
3592
|
+
projectName
|
|
3647
3593
|
);
|
|
3648
|
-
|
|
3649
|
-
|
|
3594
|
+
const commit = res[0];
|
|
3595
|
+
if (!commit || !commit.commitId) {
|
|
3596
|
+
throw new Error("no commit");
|
|
3597
|
+
}
|
|
3598
|
+
return {
|
|
3599
|
+
sha: commit.commitId,
|
|
3600
|
+
type: "COMMIT" /* COMMIT */,
|
|
3601
|
+
date: commit.committer?.date || /* @__PURE__ */ new Date()
|
|
3602
|
+
};
|
|
3603
|
+
})(),
|
|
3604
|
+
(async () => {
|
|
3605
|
+
const res = await git.getRefs(repo, projectName, `tags/${ref}`);
|
|
3606
|
+
if (!res[0] || !res[0].objectId) {
|
|
3607
|
+
throw new Error("no tag ref");
|
|
3608
|
+
}
|
|
3609
|
+
let objectId = res[0].objectId;
|
|
3610
|
+
try {
|
|
3611
|
+
const tag = await git.getAnnotatedTag(projectName, repo, objectId);
|
|
3612
|
+
if (tag.taggedObject?.objectId) {
|
|
3613
|
+
objectId = tag.taggedObject.objectId;
|
|
3614
|
+
}
|
|
3615
|
+
} catch (e) {
|
|
3616
|
+
}
|
|
3617
|
+
const commitRes2 = await git.getCommits(
|
|
3618
|
+
repo,
|
|
3619
|
+
{
|
|
3620
|
+
fromCommitId: objectId,
|
|
3621
|
+
toCommitId: objectId,
|
|
3622
|
+
$top: 1
|
|
3623
|
+
},
|
|
3624
|
+
projectName
|
|
3625
|
+
);
|
|
3626
|
+
const commit = commitRes2[0];
|
|
3627
|
+
if (!commit) {
|
|
3628
|
+
throw new Error("no commit");
|
|
3629
|
+
}
|
|
3630
|
+
return {
|
|
3631
|
+
sha: objectId,
|
|
3632
|
+
type: "TAG" /* TAG */,
|
|
3633
|
+
date: commit.committer?.date || /* @__PURE__ */ new Date()
|
|
3634
|
+
};
|
|
3635
|
+
})()
|
|
3636
|
+
]);
|
|
3637
|
+
const [branchRes, commitRes, tagRes] = results;
|
|
3638
|
+
if (tagRes.status === "fulfilled") {
|
|
3639
|
+
return tagRes.value;
|
|
3640
|
+
}
|
|
3641
|
+
if (branchRes.status === "fulfilled") {
|
|
3642
|
+
return branchRes.value;
|
|
3643
|
+
}
|
|
3644
|
+
if (commitRes.status === "fulfilled") {
|
|
3645
|
+
return commitRes.value;
|
|
3650
3646
|
}
|
|
3647
|
+
throw new RefNotFoundError(`ref: ${ref} does not exist`);
|
|
3648
|
+
},
|
|
3649
|
+
getAdoBlameRanges() {
|
|
3650
|
+
return [];
|
|
3651
3651
|
}
|
|
3652
|
-
|
|
3653
|
-
}
|
|
3654
|
-
}
|
|
3655
|
-
async function getUsersworkspacesSlugs(bitbucketClient) {
|
|
3656
|
-
const res = await bitbucketClient.workspaces.getWorkspaces({});
|
|
3657
|
-
return res.data.values?.map((v) => z8.string().parse(v.slug));
|
|
3652
|
+
};
|
|
3658
3653
|
}
|
|
3659
|
-
async function
|
|
3660
|
-
|
|
3661
|
-
|
|
3654
|
+
async function getAdoRepoList({
|
|
3655
|
+
orgName,
|
|
3656
|
+
tokenOrg,
|
|
3657
|
+
accessToken
|
|
3658
|
+
}) {
|
|
3659
|
+
let orgs = [];
|
|
3660
|
+
const adoTokenInfo = getAdoTokenInfo(accessToken);
|
|
3661
|
+
if (adoTokenInfo.type === "NONE" /* NONE */) {
|
|
3662
3662
|
return [];
|
|
3663
3663
|
}
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
const repos = await bitbucketClient.repositories.list({
|
|
3667
|
-
workspace: workspaceSlug
|
|
3668
|
-
});
|
|
3669
|
-
if (!repos.data.values) {
|
|
3670
|
-
continue;
|
|
3671
|
-
}
|
|
3672
|
-
allWorkspaceRepos.push(...repos.data.values);
|
|
3664
|
+
if (adoTokenInfo.type === "OAUTH" /* OAUTH */) {
|
|
3665
|
+
orgs = await _getOrgsForOauthToken({ oauthToken: accessToken });
|
|
3673
3666
|
}
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3667
|
+
if (orgs.length === 0 && !orgName) {
|
|
3668
|
+
throw new Error(`no orgs for ADO`);
|
|
3669
|
+
} else if (orgs.length === 0 && orgName) {
|
|
3670
|
+
orgs = [orgName];
|
|
3671
|
+
}
|
|
3672
|
+
const repos = (await Promise.allSettled(
|
|
3673
|
+
orgs.map(async (org) => {
|
|
3674
|
+
const orgApi = await getAdoApiClient({
|
|
3675
|
+
...await getAdoClientParams({
|
|
3676
|
+
accessToken,
|
|
3677
|
+
tokenOrg: tokenOrg || org,
|
|
3678
|
+
url: void 0
|
|
3679
|
+
}),
|
|
3680
|
+
orgName: org
|
|
3681
|
+
});
|
|
3682
|
+
const gitOrg = await orgApi.getGitApi();
|
|
3683
|
+
const orgRepos = await gitOrg.getRepositories();
|
|
3684
|
+
const repoInfoList = (await Promise.allSettled(
|
|
3685
|
+
orgRepos.map(async (repo) => {
|
|
3686
|
+
if (!repo.name || !repo.remoteUrl || !repo.defaultBranch) {
|
|
3687
|
+
throw new InvalidRepoUrlError("bad repo");
|
|
3688
|
+
}
|
|
3689
|
+
const branch = await gitOrg.getBranch(
|
|
3690
|
+
repo.name,
|
|
3691
|
+
repo.defaultBranch.replace(/^refs\/heads\//, ""),
|
|
3692
|
+
repo.project?.name
|
|
3693
|
+
);
|
|
3694
|
+
return {
|
|
3695
|
+
repoName: repo.name,
|
|
3696
|
+
repoUrl: repo.remoteUrl.replace(
|
|
3697
|
+
/^[hH][tT][tT][pP][sS]:\/\/[^/]+@/,
|
|
3698
|
+
"https://"
|
|
3699
|
+
),
|
|
3700
|
+
repoOwner: org,
|
|
3701
|
+
repoIsPublic: repo.project?.visibility === 2 /* Public */,
|
|
3702
|
+
repoLanguages: [],
|
|
3703
|
+
repoUpdatedAt: branch.commit?.committer?.date?.toDateString() || repo.project?.lastUpdateTime?.toDateString() || (/* @__PURE__ */ new Date()).toDateString()
|
|
3704
|
+
};
|
|
3705
|
+
})
|
|
3706
|
+
)).reduce((acc, res) => {
|
|
3707
|
+
if (res.status === "fulfilled") {
|
|
3708
|
+
acc.push(res.value);
|
|
3709
|
+
}
|
|
3710
|
+
return acc;
|
|
3711
|
+
}, []);
|
|
3712
|
+
return repoInfoList;
|
|
3713
|
+
})
|
|
3714
|
+
)).reduce((acc, res) => {
|
|
3715
|
+
if (res.status === "fulfilled") {
|
|
3716
|
+
return acc.concat(res.value);
|
|
3717
|
+
}
|
|
3718
|
+
return acc;
|
|
3719
|
+
}, []);
|
|
3720
|
+
return repos;
|
|
3681
3721
|
}
|
|
3682
3722
|
|
|
3683
3723
|
// src/features/analysis/scm/constants.ts
|
|
@@ -3686,7 +3726,7 @@ var MOBB_ICON_IMG = "https://app.mobb.ai/gh-action/Logo_Rounded_Icon.svg";
|
|
|
3686
3726
|
// src/features/analysis/add_fix_comments_for_pr/utils.ts
|
|
3687
3727
|
import Debug3 from "debug";
|
|
3688
3728
|
import parseDiff2 from "parse-diff";
|
|
3689
|
-
import { z as
|
|
3729
|
+
import { z as z10 } from "zod";
|
|
3690
3730
|
|
|
3691
3731
|
// src/features/analysis/utils/by_key.ts
|
|
3692
3732
|
function keyBy(array, keyBy2) {
|
|
@@ -3917,7 +3957,7 @@ async function getRelevantVulenrabilitiesFromDiff(params) {
|
|
|
3917
3957
|
});
|
|
3918
3958
|
const lineAddedRanges = calculateRanges(fileNumbers);
|
|
3919
3959
|
const fileFilter = {
|
|
3920
|
-
path:
|
|
3960
|
+
path: z10.string().parse(file.to),
|
|
3921
3961
|
ranges: lineAddedRanges.map(([startLine, endLine]) => ({
|
|
3922
3962
|
endLine,
|
|
3923
3963
|
startLine
|
|
@@ -4224,30 +4264,30 @@ function subscribe(query, variables, callback, wsClientOptions) {
|
|
|
4224
4264
|
}
|
|
4225
4265
|
|
|
4226
4266
|
// src/features/analysis/graphql/types.ts
|
|
4227
|
-
import { z as
|
|
4228
|
-
var VulnerabilityReportIssueCodeNodeZ =
|
|
4229
|
-
vulnerabilityReportIssueId:
|
|
4230
|
-
path:
|
|
4231
|
-
startLine:
|
|
4232
|
-
vulnerabilityReportIssue:
|
|
4233
|
-
fixId:
|
|
4267
|
+
import { z as z11 } from "zod";
|
|
4268
|
+
var VulnerabilityReportIssueCodeNodeZ = z11.object({
|
|
4269
|
+
vulnerabilityReportIssueId: z11.string(),
|
|
4270
|
+
path: z11.string(),
|
|
4271
|
+
startLine: z11.number(),
|
|
4272
|
+
vulnerabilityReportIssue: z11.object({
|
|
4273
|
+
fixId: z11.string()
|
|
4234
4274
|
})
|
|
4235
4275
|
});
|
|
4236
|
-
var GetVulByNodesMetadataZ =
|
|
4237
|
-
vulnerabilityReportIssueCodeNodes:
|
|
4238
|
-
nonFixablePrVuls:
|
|
4239
|
-
aggregate:
|
|
4240
|
-
count:
|
|
4276
|
+
var GetVulByNodesMetadataZ = z11.object({
|
|
4277
|
+
vulnerabilityReportIssueCodeNodes: z11.array(VulnerabilityReportIssueCodeNodeZ),
|
|
4278
|
+
nonFixablePrVuls: z11.object({
|
|
4279
|
+
aggregate: z11.object({
|
|
4280
|
+
count: z11.number()
|
|
4241
4281
|
})
|
|
4242
4282
|
}),
|
|
4243
|
-
fixablePrVuls:
|
|
4244
|
-
aggregate:
|
|
4245
|
-
count:
|
|
4283
|
+
fixablePrVuls: z11.object({
|
|
4284
|
+
aggregate: z11.object({
|
|
4285
|
+
count: z11.number()
|
|
4246
4286
|
})
|
|
4247
4287
|
}),
|
|
4248
|
-
totalScanVulnerabilities:
|
|
4249
|
-
aggregate:
|
|
4250
|
-
count:
|
|
4288
|
+
totalScanVulnerabilities: z11.object({
|
|
4289
|
+
aggregate: z11.object({
|
|
4290
|
+
count: z11.number()
|
|
4251
4291
|
})
|
|
4252
4292
|
})
|
|
4253
4293
|
});
|
|
@@ -5148,7 +5188,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
5148
5188
|
spinner: mobbSpinner,
|
|
5149
5189
|
submitVulnerabilityReportVariables: {
|
|
5150
5190
|
fixReportId: reportUploadInfo.fixReportId,
|
|
5151
|
-
repoUrl:
|
|
5191
|
+
repoUrl: z12.string().parse(repo),
|
|
5152
5192
|
reference,
|
|
5153
5193
|
projectId,
|
|
5154
5194
|
vulnerabilityReportFileName: "report.json",
|
|
@@ -5400,9 +5440,9 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
5400
5440
|
}
|
|
5401
5441
|
});
|
|
5402
5442
|
if (command === "review") {
|
|
5403
|
-
const params2 =
|
|
5404
|
-
repo:
|
|
5405
|
-
githubActionToken:
|
|
5443
|
+
const params2 = z12.object({
|
|
5444
|
+
repo: z12.string().url(),
|
|
5445
|
+
githubActionToken: z12.string()
|
|
5406
5446
|
}).parse({ repo, githubActionToken });
|
|
5407
5447
|
const scm2 = await SCMLib.init({
|
|
5408
5448
|
url: params2.repo,
|
|
@@ -5419,7 +5459,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
5419
5459
|
analysisId,
|
|
5420
5460
|
gqlClient,
|
|
5421
5461
|
scm: scm2,
|
|
5422
|
-
scanner:
|
|
5462
|
+
scanner: z12.nativeEnum(SCANNERS).parse(scanner)
|
|
5423
5463
|
});
|
|
5424
5464
|
},
|
|
5425
5465
|
callbackStates: ["Finished" /* Finished */]
|
|
@@ -5632,7 +5672,7 @@ var scmTokenOption = {
|
|
|
5632
5672
|
// src/args/validation.ts
|
|
5633
5673
|
import chalk6 from "chalk";
|
|
5634
5674
|
import path8 from "path";
|
|
5635
|
-
import { z as
|
|
5675
|
+
import { z as z13 } from "zod";
|
|
5636
5676
|
function throwRepoUrlErrorMessage({
|
|
5637
5677
|
error,
|
|
5638
5678
|
repoUrl,
|
|
@@ -5649,13 +5689,13 @@ Example:
|
|
|
5649
5689
|
)}`;
|
|
5650
5690
|
throw new CliError(formattedErrorMessage);
|
|
5651
5691
|
}
|
|
5652
|
-
var UrlZ =
|
|
5692
|
+
var UrlZ = z13.string({
|
|
5653
5693
|
invalid_type_error: "is not a valid GitHub / GitLab / ADO URL"
|
|
5654
5694
|
}).refine((data) => !!sanityRepoURL(data), {
|
|
5655
5695
|
message: "is not a valid GitHub / GitLab / ADO URL"
|
|
5656
5696
|
});
|
|
5657
5697
|
function validateOrganizationId(organizationId) {
|
|
5658
|
-
const orgIdValidation =
|
|
5698
|
+
const orgIdValidation = z13.string().uuid().nullish().safeParse(organizationId);
|
|
5659
5699
|
if (!orgIdValidation.success) {
|
|
5660
5700
|
throw new CliError(`organizationId: ${organizationId} is not a valid UUID`);
|
|
5661
5701
|
}
|
|
@@ -5812,7 +5852,7 @@ async function scanHandler(args) {
|
|
|
5812
5852
|
}
|
|
5813
5853
|
|
|
5814
5854
|
// src/args/commands/token.ts
|
|
5815
|
-
import { z as
|
|
5855
|
+
import { z as z14 } from "zod";
|
|
5816
5856
|
function addScmTokenBuilder(args) {
|
|
5817
5857
|
return args.option("scm-type", scmTypeOption).option("url", urlOption).option("token", scmTokenOption).option("organization", scmOrgOption).option("refresh-token", scmRefreshTokenOption).option("api-key", apiKeyOption).example(
|
|
5818
5858
|
"$0 add-scm-token --scm-type Ado --url https://dev.azure.com/adoorg/test/_git/repo --token abcdef0123456 --organization myOrg",
|
|
@@ -5820,7 +5860,7 @@ function addScmTokenBuilder(args) {
|
|
|
5820
5860
|
).help().demandOption(["url", "token"]);
|
|
5821
5861
|
}
|
|
5822
5862
|
function validateAddScmTokenOptions(argv) {
|
|
5823
|
-
if (!
|
|
5863
|
+
if (!z14.nativeEnum(ScmType).safeParse(argv.scmType).success) {
|
|
5824
5864
|
throw new CliError(
|
|
5825
5865
|
"\nError: --scm-type must reference a valid SCM type (GitHub, GitLab, Ado, Bitbutcket)"
|
|
5826
5866
|
);
|