mobbdev 1.2.24 → 1.2.27

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.
@@ -237,6 +237,7 @@ var init_client_generates = __esm({
237
237
  IssueType_Enum2["DuplicatedStrings"] = "DUPLICATED_STRINGS";
238
238
  IssueType_Enum2["ErroneousStringCompare"] = "ERRONEOUS_STRING_COMPARE";
239
239
  IssueType_Enum2["ErrorCondtionWithoutAction"] = "ERROR_CONDTION_WITHOUT_ACTION";
240
+ IssueType_Enum2["ExcessiveSecretsExposure"] = "EXCESSIVE_SECRETS_EXPOSURE";
240
241
  IssueType_Enum2["FrameableLoginPage"] = "FRAMEABLE_LOGIN_PAGE";
241
242
  IssueType_Enum2["FunctionCallWithoutParentheses"] = "FUNCTION_CALL_WITHOUT_PARENTHESES";
242
243
  IssueType_Enum2["GhActionsShellInjection"] = "GH_ACTIONS_SHELL_INJECTION";
@@ -1712,7 +1713,8 @@ var init_getIssueType = __esm({
1712
1713
  ["ACTION_NOT_PINNED_TO_COMMIT_SHA" /* ActionNotPinnedToCommitSha */]: "Action Not Pinned to Commit Sha",
1713
1714
  ["DJANGO_BLANK_FIELD_NEEDS_NULL_OR_DEFAULT" /* DjangoBlankFieldNeedsNullOrDefault */]: "Django Blank Field Needs Null or Default",
1714
1715
  ["REDUNDANT_NIL_ERROR_CHECK" /* RedundantNilErrorCheck */]: "Redundant Nil Error Check",
1715
- ["MISSING_WORKFLOW_PERMISSIONS" /* MissingWorkflowPermissions */]: "Missing Workflow Permissions"
1716
+ ["MISSING_WORKFLOW_PERMISSIONS" /* MissingWorkflowPermissions */]: "Missing Workflow Permissions",
1717
+ ["EXCESSIVE_SECRETS_EXPOSURE" /* ExcessiveSecretsExposure */]: "Excessive Secrets Exposure"
1716
1718
  };
1717
1719
  issueTypeZ = z5.nativeEnum(IssueType_Enum);
1718
1720
  getIssueTypeFriendlyString = (issueType) => {
@@ -4556,7 +4558,8 @@ var fixDetailsData = {
4556
4558
  ["ACTION_NOT_PINNED_TO_COMMIT_SHA" /* ActionNotPinnedToCommitSha */]: void 0,
4557
4559
  ["DJANGO_BLANK_FIELD_NEEDS_NULL_OR_DEFAULT" /* DjangoBlankFieldNeedsNullOrDefault */]: void 0,
4558
4560
  ["REDUNDANT_NIL_ERROR_CHECK" /* RedundantNilErrorCheck */]: void 0,
4559
- ["MISSING_WORKFLOW_PERMISSIONS" /* MissingWorkflowPermissions */]: void 0
4561
+ ["MISSING_WORKFLOW_PERMISSIONS" /* MissingWorkflowPermissions */]: void 0,
4562
+ ["EXCESSIVE_SECRETS_EXPOSURE" /* ExcessiveSecretsExposure */]: void 0
4560
4563
  };
4561
4564
 
4562
4565
  // src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
package/dist/index.mjs CHANGED
@@ -237,6 +237,7 @@ var init_client_generates = __esm({
237
237
  IssueType_Enum2["DuplicatedStrings"] = "DUPLICATED_STRINGS";
238
238
  IssueType_Enum2["ErroneousStringCompare"] = "ERRONEOUS_STRING_COMPARE";
239
239
  IssueType_Enum2["ErrorCondtionWithoutAction"] = "ERROR_CONDTION_WITHOUT_ACTION";
240
+ IssueType_Enum2["ExcessiveSecretsExposure"] = "EXCESSIVE_SECRETS_EXPOSURE";
240
241
  IssueType_Enum2["FrameableLoginPage"] = "FRAMEABLE_LOGIN_PAGE";
241
242
  IssueType_Enum2["FunctionCallWithoutParentheses"] = "FUNCTION_CALL_WITHOUT_PARENTHESES";
242
243
  IssueType_Enum2["GhActionsShellInjection"] = "GH_ACTIONS_SHELL_INJECTION";
@@ -1412,7 +1413,8 @@ var init_getIssueType = __esm({
1412
1413
  ["ACTION_NOT_PINNED_TO_COMMIT_SHA" /* ActionNotPinnedToCommitSha */]: "Action Not Pinned to Commit Sha",
1413
1414
  ["DJANGO_BLANK_FIELD_NEEDS_NULL_OR_DEFAULT" /* DjangoBlankFieldNeedsNullOrDefault */]: "Django Blank Field Needs Null or Default",
1414
1415
  ["REDUNDANT_NIL_ERROR_CHECK" /* RedundantNilErrorCheck */]: "Redundant Nil Error Check",
1415
- ["MISSING_WORKFLOW_PERMISSIONS" /* MissingWorkflowPermissions */]: "Missing Workflow Permissions"
1416
+ ["MISSING_WORKFLOW_PERMISSIONS" /* MissingWorkflowPermissions */]: "Missing Workflow Permissions",
1417
+ ["EXCESSIVE_SECRETS_EXPOSURE" /* ExcessiveSecretsExposure */]: "Excessive Secrets Exposure"
1416
1418
  };
1417
1419
  issueTypeZ = z.nativeEnum(IssueType_Enum);
1418
1420
  getIssueTypeFriendlyString = (issueType) => {
@@ -4284,7 +4286,8 @@ var fixDetailsData = {
4284
4286
  ["ACTION_NOT_PINNED_TO_COMMIT_SHA" /* ActionNotPinnedToCommitSha */]: void 0,
4285
4287
  ["DJANGO_BLANK_FIELD_NEEDS_NULL_OR_DEFAULT" /* DjangoBlankFieldNeedsNullOrDefault */]: void 0,
4286
4288
  ["REDUNDANT_NIL_ERROR_CHECK" /* RedundantNilErrorCheck */]: void 0,
4287
- ["MISSING_WORKFLOW_PERMISSIONS" /* MissingWorkflowPermissions */]: void 0
4289
+ ["MISSING_WORKFLOW_PERMISSIONS" /* MissingWorkflowPermissions */]: void 0,
4290
+ ["EXCESSIVE_SECRETS_EXPOSURE" /* ExcessiveSecretsExposure */]: void 0
4288
4291
  };
4289
4292
 
4290
4293
  // src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
@@ -9565,34 +9568,74 @@ async function getGitlabIsRemoteBranch({
9565
9568
  return false;
9566
9569
  }
9567
9570
  }
9568
- async function getGitlabRepoList(url, accessToken) {
9571
+ async function searchGitlabProjects({
9572
+ url,
9573
+ accessToken,
9574
+ perPage = 20,
9575
+ page = 1
9576
+ }) {
9577
+ if (perPage > GITLAB_MAX_PER_PAGE) {
9578
+ throw new Error(
9579
+ `perPage ${perPage} exceeds GitLab maximum of ${GITLAB_MAX_PER_PAGE}`
9580
+ );
9581
+ }
9569
9582
  const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
9570
- const res = await api2.Projects.all({
9571
- membership: true,
9572
- //TODO: a bug in the sorting mechanism of this api call
9573
- //disallows us to sort by updated_at in descending order
9574
- //so we have to sort by updated_at in ascending order.
9575
- //We can wait for the bug to be fixed or call the api
9576
- //directly with fetch()
9577
- sort: "asc",
9578
- orderBy: "updated_at",
9579
- perPage: 100
9580
- });
9581
- return Promise.all(
9582
- res.map(async (project) => {
9583
- const proj = await api2.Projects.show(project.id);
9584
- const owner = proj.namespace.name;
9585
- const repoLanguages = await api2.Projects.showLanguages(project.id);
9586
- return {
9587
- repoName: project.path,
9588
- repoUrl: project.web_url,
9589
- repoOwner: owner,
9590
- repoLanguages: Object.keys(repoLanguages),
9591
- repoIsPublic: project.visibility === "public",
9592
- repoUpdatedAt: project.last_activity_at
9593
- };
9594
- })
9595
- );
9583
+ let response;
9584
+ try {
9585
+ response = await api2.Projects.all({
9586
+ membership: true,
9587
+ orderBy: "last_activity_at",
9588
+ sort: "desc",
9589
+ pagination: "offset",
9590
+ perPage,
9591
+ page,
9592
+ showExpanded: true
9593
+ });
9594
+ } catch (e) {
9595
+ debug4(
9596
+ "[searchGitlabProjects] order_by=last_activity_at failed, falling back to created_at: %s",
9597
+ e instanceof Error ? e.message : String(e)
9598
+ );
9599
+ response = await api2.Projects.all({
9600
+ membership: true,
9601
+ orderBy: "created_at",
9602
+ sort: "desc",
9603
+ pagination: "offset",
9604
+ perPage,
9605
+ page,
9606
+ showExpanded: true
9607
+ });
9608
+ }
9609
+ const projects = response.data.map((p) => ({
9610
+ id: p.id,
9611
+ path: p.path,
9612
+ web_url: p.web_url,
9613
+ namespace_name: p.namespace?.name ?? "",
9614
+ visibility: p.visibility,
9615
+ last_activity_at: p.last_activity_at
9616
+ }));
9617
+ return {
9618
+ projects,
9619
+ hasMore: response.paginationInfo.next !== null
9620
+ };
9621
+ }
9622
+ async function getGitlabProjectLanguages({
9623
+ url,
9624
+ accessToken,
9625
+ projectId
9626
+ }) {
9627
+ try {
9628
+ const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
9629
+ const languages3 = await api2.Projects.showLanguages(projectId);
9630
+ return Object.keys(languages3);
9631
+ } catch (e) {
9632
+ debug4(
9633
+ "[getGitlabProjectLanguages] Failed for project %d: %s",
9634
+ projectId,
9635
+ e instanceof Error ? e.message : String(e)
9636
+ );
9637
+ return [];
9638
+ }
9596
9639
  }
9597
9640
  async function getGitlabBranchList({
9598
9641
  accessToken,
@@ -9662,6 +9705,11 @@ async function searchGitlabMergeRequests({
9662
9705
  perPage = GITLAB_PER_PAGE,
9663
9706
  page = 1
9664
9707
  }) {
9708
+ if (perPage > GITLAB_MAX_PER_PAGE) {
9709
+ throw new Error(
9710
+ `perPage ${perPage} exceeds GitLab maximum of ${GITLAB_MAX_PER_PAGE}`
9711
+ );
9712
+ }
9665
9713
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
9666
9714
  debug4(
9667
9715
  "[searchGitlabMergeRequests] Fetching MRs for %s (page=%d, perPage=%d)",
@@ -9673,16 +9721,17 @@ async function searchGitlabMergeRequests({
9673
9721
  url: repoUrl,
9674
9722
  gitlabAuthToken: accessToken
9675
9723
  });
9676
- const mergeRequests = await api2.MergeRequests.all({
9724
+ const response = await api2.MergeRequests.all({
9677
9725
  projectId: projectPath,
9678
9726
  state: state === "all" ? void 0 : state,
9679
9727
  updatedAfter: updatedAfter?.toISOString(),
9680
9728
  orderBy,
9681
9729
  sort,
9682
9730
  perPage,
9683
- page
9731
+ page,
9732
+ showExpanded: true
9684
9733
  });
9685
- const items = mergeRequests.map((mr) => ({
9734
+ const items = response.data.map((mr) => ({
9686
9735
  iid: mr.iid,
9687
9736
  title: mr.title,
9688
9737
  state: mr.state,
@@ -9700,7 +9749,7 @@ async function searchGitlabMergeRequests({
9700
9749
  );
9701
9750
  return {
9702
9751
  items,
9703
- hasMore: mergeRequests.length === perPage
9752
+ hasMore: response.paginationInfo.next !== null
9704
9753
  };
9705
9754
  }
9706
9755
  var GITLAB_API_CONCURRENCY = 5;
@@ -9897,7 +9946,8 @@ function parseGitlabOwnerAndRepo(gitlabUrl) {
9897
9946
  return { owner: organization, repo: repoName, projectPath };
9898
9947
  }
9899
9948
  var GITLAB_MAX_RESULTS_LIMIT = 1024;
9900
- var GITLAB_PER_PAGE = 128;
9949
+ var GITLAB_MAX_PER_PAGE = 100;
9950
+ var GITLAB_PER_PAGE = GITLAB_MAX_PER_PAGE;
9901
9951
  async function getGitlabRecentCommits({
9902
9952
  repoUrl,
9903
9953
  accessToken,
@@ -9906,14 +9956,17 @@ async function getGitlabRecentCommits({
9906
9956
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
9907
9957
  const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
9908
9958
  const allCommits = [];
9959
+ const perPage = GITLAB_PER_PAGE;
9909
9960
  let page = 1;
9910
9961
  let hasMore = true;
9911
9962
  while (hasMore && allCommits.length < GITLAB_MAX_RESULTS_LIMIT) {
9912
- const commits = await api2.Commits.all(projectPath, {
9963
+ const response = await api2.Commits.all(projectPath, {
9913
9964
  since,
9914
- perPage: GITLAB_PER_PAGE,
9915
- page
9965
+ perPage,
9966
+ page,
9967
+ showExpanded: true
9916
9968
  });
9969
+ const commits = response.data;
9917
9970
  if (commits.length === 0) {
9918
9971
  hasMore = false;
9919
9972
  break;
@@ -9935,11 +9988,8 @@ async function getGitlabRecentCommits({
9935
9988
  parents: commit.parent_ids?.map((sha) => ({ sha })) || []
9936
9989
  });
9937
9990
  }
9938
- if (commits.length < GITLAB_PER_PAGE) {
9939
- hasMore = false;
9940
- } else {
9941
- page++;
9942
- }
9991
+ hasMore = response.paginationInfo.next !== null;
9992
+ page++;
9943
9993
  }
9944
9994
  if (allCommits.length >= GITLAB_MAX_RESULTS_LIMIT) {
9945
9995
  contextLogger.warn("[getGitlabRecentCommits] Hit commit pagination limit", {
@@ -10064,7 +10114,20 @@ var GitlabSCMLib = class extends SCMLib {
10064
10114
  contextLogger.warn("[GitlabSCMLib.getRepoList] No access token provided");
10065
10115
  throw new Error("no access token");
10066
10116
  }
10067
- return getGitlabRepoList(this.url, this.accessToken);
10117
+ const allRepos = [];
10118
+ let cursor;
10119
+ let hasMore = true;
10120
+ while (hasMore) {
10121
+ const page = await this.searchRepos({
10122
+ scmOrg: _scmOrg,
10123
+ limit: 100,
10124
+ cursor
10125
+ });
10126
+ allRepos.push(...page.results);
10127
+ hasMore = page.hasMore;
10128
+ cursor = page.nextCursor;
10129
+ }
10130
+ return allRepos;
10068
10131
  }
10069
10132
  async getBranchList() {
10070
10133
  this._validateAccessTokenAndUrl();
@@ -10294,8 +10357,47 @@ var GitlabSCMLib = class extends SCMLib {
10294
10357
  mrNumbers: prNumbers
10295
10358
  });
10296
10359
  }
10297
- async searchRepos(_params) {
10298
- throw new Error("searchRepos not implemented for GitLab");
10360
+ async searchRepos(params) {
10361
+ if (!this.accessToken) {
10362
+ throw new Error("no access token");
10363
+ }
10364
+ const page = parseCursorSafe(params.cursor, 1);
10365
+ const perPage = params.limit || 10;
10366
+ const { projects, hasMore } = await searchGitlabProjects({
10367
+ url: this.url,
10368
+ accessToken: this.accessToken,
10369
+ perPage,
10370
+ page
10371
+ });
10372
+ const includeLanguages = params.includeLanguages !== false;
10373
+ const languageMap = /* @__PURE__ */ new Map();
10374
+ if (includeLanguages && projects.length > 0) {
10375
+ const languageResults = await Promise.all(
10376
+ projects.map(
10377
+ (p) => getGitlabProjectLanguages({
10378
+ url: this.url,
10379
+ accessToken: this.accessToken,
10380
+ projectId: p.id
10381
+ }).then((langs) => [p.id, langs])
10382
+ )
10383
+ );
10384
+ for (const [id, langs] of languageResults) {
10385
+ languageMap.set(id, langs);
10386
+ }
10387
+ }
10388
+ const results = projects.map((p) => ({
10389
+ repoName: p.path,
10390
+ repoUrl: p.web_url,
10391
+ repoOwner: p.namespace_name,
10392
+ repoLanguages: languageMap.get(p.id) || [],
10393
+ repoIsPublic: p.visibility === "public",
10394
+ repoUpdatedAt: p.last_activity_at
10395
+ }));
10396
+ return {
10397
+ results,
10398
+ nextCursor: hasMore ? String(page + 1) : void 0,
10399
+ hasMore
10400
+ };
10299
10401
  }
10300
10402
  async getPullRequestMetrics(prNumber) {
10301
10403
  this._validateAccessTokenAndUrl();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "1.2.24",
3
+ "version": "1.2.27",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "git+https://github.com/mobb-dev/bugsy.git",
6
6
  "main": "dist/index.mjs",