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