mobbdev 1.0.191 → 1.0.194
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/args/commands/upload_ai_blame.mjs +8 -2
- package/dist/index.mjs +439 -86
- package/package.json +1 -1
|
@@ -659,6 +659,9 @@ var GetAnalysisDocument = `
|
|
|
659
659
|
projectId
|
|
660
660
|
project {
|
|
661
661
|
organizationId
|
|
662
|
+
organization {
|
|
663
|
+
ghFixerNoFixComments
|
|
664
|
+
}
|
|
662
665
|
}
|
|
663
666
|
file {
|
|
664
667
|
signedFile {
|
|
@@ -4123,7 +4126,7 @@ var scmTypeToScmLibScmType = {
|
|
|
4123
4126
|
["Ado" /* Ado */]: "ADO" /* ADO */,
|
|
4124
4127
|
["Bitbucket" /* Bitbucket */]: "BITBUCKET" /* BITBUCKET */
|
|
4125
4128
|
};
|
|
4126
|
-
var
|
|
4129
|
+
var GetReferenceResultZ = z14.object({
|
|
4127
4130
|
date: z14.date().optional(),
|
|
4128
4131
|
sha: z14.string(),
|
|
4129
4132
|
type: z14.nativeEnum(ReferenceType)
|
|
@@ -4744,6 +4747,8 @@ var VulnerabilityReportSchema = z26.object({
|
|
|
4744
4747
|
// GraphQL uses `any` type for timestamp
|
|
4745
4748
|
vendor: z26.string(),
|
|
4746
4749
|
// GraphQL generates as string, not enum
|
|
4750
|
+
projectId: z26.any().optional(),
|
|
4751
|
+
// GraphQL uses `any` type for UUID
|
|
4747
4752
|
project: ProjectSchema,
|
|
4748
4753
|
totalVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema,
|
|
4749
4754
|
notFixableVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema
|
|
@@ -5243,7 +5248,7 @@ var McpGQLClient = class {
|
|
|
5243
5248
|
const reportMetadata = {
|
|
5244
5249
|
id: reportData.id,
|
|
5245
5250
|
organizationId: reportData.vulnerabilityReport?.project?.organizationId,
|
|
5246
|
-
projectId: reportData.vulnerabilityReport?.
|
|
5251
|
+
projectId: reportData.vulnerabilityReport?.projectId
|
|
5247
5252
|
};
|
|
5248
5253
|
const { userFixes = [], fixes = [] } = reportData;
|
|
5249
5254
|
const fixMap = /* @__PURE__ */ new Map();
|
|
@@ -5460,6 +5465,7 @@ var McpGQLClient = class {
|
|
|
5460
5465
|
reportData: latestReport,
|
|
5461
5466
|
limit
|
|
5462
5467
|
});
|
|
5468
|
+
logDebug("[GraphQL] GetReportFixes response parsed", { fixes });
|
|
5463
5469
|
return {
|
|
5464
5470
|
fixes,
|
|
5465
5471
|
totalCount: res.fixReport?.[0]?.filteredFixesCount?.aggregate?.count || 0,
|
package/dist/index.mjs
CHANGED
|
@@ -2094,6 +2094,9 @@ var GetAnalysisDocument = `
|
|
|
2094
2094
|
projectId
|
|
2095
2095
|
project {
|
|
2096
2096
|
organizationId
|
|
2097
|
+
organization {
|
|
2098
|
+
ghFixerNoFixComments
|
|
2099
|
+
}
|
|
2097
2100
|
}
|
|
2098
2101
|
file {
|
|
2099
2102
|
signedFile {
|
|
@@ -5793,7 +5796,7 @@ var scmTypeToScmLibScmType = {
|
|
|
5793
5796
|
["Ado" /* Ado */]: "ADO" /* ADO */,
|
|
5794
5797
|
["Bitbucket" /* Bitbucket */]: "BITBUCKET" /* BITBUCKET */
|
|
5795
5798
|
};
|
|
5796
|
-
var
|
|
5799
|
+
var GetReferenceResultZ = z13.object({
|
|
5797
5800
|
date: z13.date().optional(),
|
|
5798
5801
|
sha: z13.string(),
|
|
5799
5802
|
type: z13.nativeEnum(ReferenceType)
|
|
@@ -6764,7 +6767,7 @@ var AdoSCMLib = class extends SCMLib {
|
|
|
6764
6767
|
return String(pullRequestId);
|
|
6765
6768
|
} catch (e) {
|
|
6766
6769
|
console.warn(
|
|
6767
|
-
`error creating pull request for ADO. Try number ${i + 1}`,
|
|
6770
|
+
`error creating pull request for ADO. Try number ${String(i + 1).replace(/\n|\r/g, "")}`,
|
|
6768
6771
|
e
|
|
6769
6772
|
);
|
|
6770
6773
|
await setTimeout2(1e3);
|
|
@@ -6924,6 +6927,12 @@ var AdoSCMLib = class extends SCMLib {
|
|
|
6924
6927
|
async getCommitDiff(_commitSha) {
|
|
6925
6928
|
throw new Error("getCommitDiff not implemented for ADO");
|
|
6926
6929
|
}
|
|
6930
|
+
async getSubmitRequestDiff(_submitRequestId) {
|
|
6931
|
+
throw new Error("getSubmitRequestDiff not implemented for ADO");
|
|
6932
|
+
}
|
|
6933
|
+
async getSubmitRequests(_repoUrl) {
|
|
6934
|
+
throw new Error("getSubmitRequests not implemented for ADO");
|
|
6935
|
+
}
|
|
6927
6936
|
};
|
|
6928
6937
|
|
|
6929
6938
|
// src/features/analysis/scm/bitbucket/bitbucket.ts
|
|
@@ -6969,15 +6978,15 @@ function parseBitbucketOrganizationAndRepo(bitbucketUrl) {
|
|
|
6969
6978
|
repo_slug: validatedBitbucketResult.repoName
|
|
6970
6979
|
};
|
|
6971
6980
|
}
|
|
6972
|
-
function
|
|
6973
|
-
const
|
|
6981
|
+
function getBitbucketInstance(params) {
|
|
6982
|
+
const BitbucketConstructor = bitbucketPkg && "Bitbucket" in bitbucketPkg ? bitbucketPkg.Bitbucket : bitbucketPkgNode.Bitbucket;
|
|
6974
6983
|
switch (params.authType) {
|
|
6975
6984
|
case "public":
|
|
6976
|
-
return new
|
|
6985
|
+
return new BitbucketConstructor();
|
|
6977
6986
|
case "token":
|
|
6978
|
-
return new
|
|
6987
|
+
return new BitbucketConstructor({ auth: { token: params.token } });
|
|
6979
6988
|
case "basic":
|
|
6980
|
-
return new
|
|
6989
|
+
return new BitbucketConstructor({
|
|
6981
6990
|
auth: {
|
|
6982
6991
|
password: params.password,
|
|
6983
6992
|
username: params.username
|
|
@@ -6986,7 +6995,7 @@ function getBitbucketIntance(params) {
|
|
|
6986
6995
|
}
|
|
6987
6996
|
}
|
|
6988
6997
|
function getBitbucketSdk(params) {
|
|
6989
|
-
const bitbucketClient =
|
|
6998
|
+
const bitbucketClient = getBitbucketInstance(params);
|
|
6990
6999
|
return {
|
|
6991
7000
|
getAuthType() {
|
|
6992
7001
|
return params.authType;
|
|
@@ -6994,12 +7003,11 @@ function getBitbucketSdk(params) {
|
|
|
6994
7003
|
async getRepos(params2) {
|
|
6995
7004
|
const repoRes = params2?.workspaceSlug ? await getRepositoriesByWorkspace(bitbucketClient, {
|
|
6996
7005
|
workspaceSlug: params2.workspaceSlug
|
|
6997
|
-
}) : await
|
|
7006
|
+
}) : await getAllUsersRepositories(bitbucketClient);
|
|
6998
7007
|
return repoRes.map((repo) => ({
|
|
6999
7008
|
repoIsPublic: !repo.is_private,
|
|
7000
7009
|
repoName: repo.name || "unknown repo name",
|
|
7001
7010
|
repoOwner: repo.owner?.username || "unknown owner",
|
|
7002
|
-
// language can be empty string
|
|
7003
7011
|
repoLanguages: repo.language ? [repo.language] : [],
|
|
7004
7012
|
repoUpdatedAt: repo.updated_on ? repo.updated_on : (/* @__PURE__ */ new Date()).toISOString(),
|
|
7005
7013
|
repoUrl: repo.links?.html?.href || ""
|
|
@@ -7059,7 +7067,7 @@ function getBitbucketSdk(params) {
|
|
|
7059
7067
|
});
|
|
7060
7068
|
return res.data;
|
|
7061
7069
|
},
|
|
7062
|
-
async
|
|
7070
|
+
async getDownloadLink(params2) {
|
|
7063
7071
|
const { repo_slug, workspace } = parseBitbucketOrganizationAndRepo(
|
|
7064
7072
|
params2.repoUrl
|
|
7065
7073
|
);
|
|
@@ -7131,7 +7139,7 @@ function getBitbucketSdk(params) {
|
|
|
7131
7139
|
workspace,
|
|
7132
7140
|
name: tagName
|
|
7133
7141
|
});
|
|
7134
|
-
return
|
|
7142
|
+
return GetReferenceResultZ.parse({
|
|
7135
7143
|
sha: tagRes.data.target?.hash,
|
|
7136
7144
|
type: "TAG" /* TAG */,
|
|
7137
7145
|
date: new Date(z19.string().parse(tagRes.data.target?.date))
|
|
@@ -7139,7 +7147,7 @@ function getBitbucketSdk(params) {
|
|
|
7139
7147
|
},
|
|
7140
7148
|
async getBranchRef(params2) {
|
|
7141
7149
|
const getBranchRes = await this.getBranch(params2);
|
|
7142
|
-
return
|
|
7150
|
+
return GetReferenceResultZ.parse({
|
|
7143
7151
|
sha: getBranchRes.target?.hash,
|
|
7144
7152
|
type: "BRANCH" /* BRANCH */,
|
|
7145
7153
|
date: new Date(z19.string().parse(getBranchRes.target?.date))
|
|
@@ -7147,7 +7155,7 @@ function getBitbucketSdk(params) {
|
|
|
7147
7155
|
},
|
|
7148
7156
|
async getCommitRef(params2) {
|
|
7149
7157
|
const getCommitRes = await this.getCommit(params2);
|
|
7150
|
-
return
|
|
7158
|
+
return GetReferenceResultZ.parse({
|
|
7151
7159
|
sha: getCommitRes.hash,
|
|
7152
7160
|
type: "COMMIT" /* COMMIT */,
|
|
7153
7161
|
date: new Date(z19.string().parse(getCommitRes.date))
|
|
@@ -7177,7 +7185,7 @@ function getBitbucketSdk(params) {
|
|
|
7177
7185
|
}) {
|
|
7178
7186
|
const { repo_slug, workspace } = parseBitbucketOrganizationAndRepo(url);
|
|
7179
7187
|
const res = await bitbucketClient.pullrequests.createComment({
|
|
7180
|
-
//@ts-expect-error
|
|
7188
|
+
//@ts-expect-error type requires _body.type, but it its uses api fails
|
|
7181
7189
|
_body: {
|
|
7182
7190
|
content: {
|
|
7183
7191
|
raw: markdownComment
|
|
@@ -7219,17 +7227,17 @@ async function validateBitbucketParams(params) {
|
|
|
7219
7227
|
);
|
|
7220
7228
|
}
|
|
7221
7229
|
}
|
|
7222
|
-
async function
|
|
7230
|
+
async function getUsersWorkspacesSlugs(bitbucketClient) {
|
|
7223
7231
|
const res = await bitbucketClient.workspaces.getWorkspaces({});
|
|
7224
7232
|
return res.data.values?.map((v) => z19.string().parse(v.slug));
|
|
7225
7233
|
}
|
|
7226
|
-
async function
|
|
7227
|
-
const
|
|
7228
|
-
if (!
|
|
7234
|
+
async function getAllUsersRepositories(bitbucketClient) {
|
|
7235
|
+
const userWorkspacesSlugs = await getUsersWorkspacesSlugs(bitbucketClient);
|
|
7236
|
+
if (!userWorkspacesSlugs) {
|
|
7229
7237
|
return [];
|
|
7230
7238
|
}
|
|
7231
7239
|
const allWorkspaceRepos = [];
|
|
7232
|
-
for (const workspaceSlug of
|
|
7240
|
+
for (const workspaceSlug of userWorkspacesSlugs) {
|
|
7233
7241
|
const repos = await bitbucketClient.repositories.list({
|
|
7234
7242
|
workspace: workspaceSlug
|
|
7235
7243
|
});
|
|
@@ -7490,6 +7498,12 @@ var BitbucketSCMLib = class extends SCMLib {
|
|
|
7490
7498
|
async getCommitDiff(_commitSha) {
|
|
7491
7499
|
throw new Error("getCommitDiff not implemented for Bitbucket");
|
|
7492
7500
|
}
|
|
7501
|
+
async getSubmitRequestDiff(_submitRequestId) {
|
|
7502
|
+
throw new Error("getSubmitRequestDiff not implemented for Bitbucket");
|
|
7503
|
+
}
|
|
7504
|
+
async getSubmitRequests(_repoUrl) {
|
|
7505
|
+
throw new Error("getSubmitRequests not implemented for Bitbucket");
|
|
7506
|
+
}
|
|
7493
7507
|
};
|
|
7494
7508
|
|
|
7495
7509
|
// src/features/analysis/scm/constants.ts
|
|
@@ -8084,6 +8098,31 @@ function getGithubSdk(params = {}) {
|
|
|
8084
8098
|
},
|
|
8085
8099
|
async getUserInfo() {
|
|
8086
8100
|
return octokit.request(GET_USER);
|
|
8101
|
+
},
|
|
8102
|
+
async getPrCommits(params2) {
|
|
8103
|
+
return octokit.rest.pulls.listCommits({
|
|
8104
|
+
owner: params2.owner,
|
|
8105
|
+
repo: params2.repo,
|
|
8106
|
+
pull_number: params2.pull_number
|
|
8107
|
+
});
|
|
8108
|
+
},
|
|
8109
|
+
async getUserRepos() {
|
|
8110
|
+
return octokit.rest.repos.listForAuthenticatedUser({
|
|
8111
|
+
visibility: "all",
|
|
8112
|
+
affiliation: "owner,collaborator,organization_member",
|
|
8113
|
+
sort: "updated",
|
|
8114
|
+
per_page: 100
|
|
8115
|
+
});
|
|
8116
|
+
},
|
|
8117
|
+
async getRepoPullRequests(params2) {
|
|
8118
|
+
return octokit.rest.pulls.list({
|
|
8119
|
+
owner: params2.owner,
|
|
8120
|
+
repo: params2.repo,
|
|
8121
|
+
state: "all",
|
|
8122
|
+
sort: "updated",
|
|
8123
|
+
direction: "desc",
|
|
8124
|
+
per_page: 100
|
|
8125
|
+
});
|
|
8087
8126
|
}
|
|
8088
8127
|
};
|
|
8089
8128
|
}
|
|
@@ -8362,6 +8401,284 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
8362
8401
|
message: commit.commit.message
|
|
8363
8402
|
};
|
|
8364
8403
|
}
|
|
8404
|
+
async getSubmitRequestDiff(submitRequestId) {
|
|
8405
|
+
this._validateAccessTokenAndUrl();
|
|
8406
|
+
const { owner, repo } = parseGithubOwnerAndRepo(this.url);
|
|
8407
|
+
const prNumber = Number(submitRequestId);
|
|
8408
|
+
const prRes = await this.githubSdk.getPr({
|
|
8409
|
+
owner,
|
|
8410
|
+
repo,
|
|
8411
|
+
pull_number: prNumber
|
|
8412
|
+
});
|
|
8413
|
+
const prDiff = await this.getPrDiff({ pull_number: prNumber });
|
|
8414
|
+
const commitsRes = await this.githubSdk.getPrCommits({
|
|
8415
|
+
owner,
|
|
8416
|
+
repo,
|
|
8417
|
+
pull_number: prNumber
|
|
8418
|
+
});
|
|
8419
|
+
const commits = [];
|
|
8420
|
+
for (const commit of commitsRes.data) {
|
|
8421
|
+
const commitDiff = await this.getCommitDiff(commit.sha);
|
|
8422
|
+
commits.push(commitDiff);
|
|
8423
|
+
}
|
|
8424
|
+
const pr = prRes.data;
|
|
8425
|
+
const diffLines = this._calculateDiffLineAttributions(prDiff, commits);
|
|
8426
|
+
return {
|
|
8427
|
+
diff: prDiff,
|
|
8428
|
+
createdAt: new Date(pr.created_at),
|
|
8429
|
+
updatedAt: new Date(pr.updated_at),
|
|
8430
|
+
submitRequestId,
|
|
8431
|
+
submitRequestNumber: prNumber,
|
|
8432
|
+
sourceBranch: pr.head.ref,
|
|
8433
|
+
targetBranch: pr.base.ref,
|
|
8434
|
+
authorName: pr.user?.name || pr.user?.login,
|
|
8435
|
+
authorEmail: pr.user?.email || void 0,
|
|
8436
|
+
title: pr.title,
|
|
8437
|
+
description: pr.body || void 0,
|
|
8438
|
+
commits,
|
|
8439
|
+
diffLines
|
|
8440
|
+
};
|
|
8441
|
+
}
|
|
8442
|
+
async getSubmitRequests(repoUrl) {
|
|
8443
|
+
this._validateAccessToken();
|
|
8444
|
+
const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
|
|
8445
|
+
const pullsRes = await this.githubSdk.getRepoPullRequests({ owner, repo });
|
|
8446
|
+
const submitRequests = await Promise.all(
|
|
8447
|
+
pullsRes.data.map(async (pr) => {
|
|
8448
|
+
let status = "open";
|
|
8449
|
+
if (pr.state === "closed") {
|
|
8450
|
+
status = pr.merged_at ? "merged" : "closed";
|
|
8451
|
+
} else if (pr.draft) {
|
|
8452
|
+
status = "draft";
|
|
8453
|
+
}
|
|
8454
|
+
const [tickets, changedLines] = await Promise.all([
|
|
8455
|
+
this._extractLinearTicketsFromPR(owner, repo, pr.number),
|
|
8456
|
+
this._calculateChangedLinesFromPR(owner, repo, pr.number)
|
|
8457
|
+
]);
|
|
8458
|
+
return {
|
|
8459
|
+
submitRequestId: String(pr.number),
|
|
8460
|
+
submitRequestNumber: pr.number,
|
|
8461
|
+
title: pr.title,
|
|
8462
|
+
status,
|
|
8463
|
+
sourceBranch: pr.head.ref,
|
|
8464
|
+
targetBranch: pr.base.ref,
|
|
8465
|
+
authorName: pr.user?.name || pr.user?.login,
|
|
8466
|
+
authorEmail: pr.user?.email || void 0,
|
|
8467
|
+
createdAt: new Date(pr.created_at),
|
|
8468
|
+
updatedAt: new Date(pr.updated_at),
|
|
8469
|
+
description: pr.body || void 0,
|
|
8470
|
+
tickets,
|
|
8471
|
+
changedLines
|
|
8472
|
+
};
|
|
8473
|
+
})
|
|
8474
|
+
);
|
|
8475
|
+
return submitRequests;
|
|
8476
|
+
}
|
|
8477
|
+
async _extractLinearTicketsFromPR(owner, repo, prNumber) {
|
|
8478
|
+
try {
|
|
8479
|
+
const commentsRes = await this.githubSdk.getGeneralPrComments({
|
|
8480
|
+
owner,
|
|
8481
|
+
repo,
|
|
8482
|
+
issue_number: prNumber
|
|
8483
|
+
});
|
|
8484
|
+
const tickets = [];
|
|
8485
|
+
for (const comment of commentsRes.data) {
|
|
8486
|
+
if (comment.user?.login === "linear[bot]" || comment.user?.type === "Bot") {
|
|
8487
|
+
const htmlLinkPattern = /<a href="(https:\/\/linear\.app\/[^"]+)">([A-Z]+-\d+)<\/a>/g;
|
|
8488
|
+
let match;
|
|
8489
|
+
while ((match = htmlLinkPattern.exec(comment.body || "")) !== null) {
|
|
8490
|
+
const url = match[1];
|
|
8491
|
+
const name = match[2];
|
|
8492
|
+
if (!name || !url) {
|
|
8493
|
+
continue;
|
|
8494
|
+
}
|
|
8495
|
+
const urlParts = url.split("/");
|
|
8496
|
+
const titleSlug = urlParts[urlParts.length - 1] || "";
|
|
8497
|
+
const title = titleSlug.replace(/-/g, " ");
|
|
8498
|
+
tickets.push({ name, title, url });
|
|
8499
|
+
}
|
|
8500
|
+
const markdownLinkPattern = /\[([A-Z]+-\d+)\]\((https:\/\/linear\.app\/[^)]+)\)/g;
|
|
8501
|
+
while ((match = markdownLinkPattern.exec(comment.body || "")) !== null) {
|
|
8502
|
+
const name = match[1];
|
|
8503
|
+
const url = match[2];
|
|
8504
|
+
if (tickets.some((t) => t.name === name && t.url === url)) {
|
|
8505
|
+
continue;
|
|
8506
|
+
}
|
|
8507
|
+
if (!name || !url) {
|
|
8508
|
+
continue;
|
|
8509
|
+
}
|
|
8510
|
+
const urlParts = url.split("/");
|
|
8511
|
+
const titleSlug = urlParts[urlParts.length - 1] || "";
|
|
8512
|
+
const title = titleSlug.replace(/-/g, " ");
|
|
8513
|
+
tickets.push({ name, title, url });
|
|
8514
|
+
}
|
|
8515
|
+
}
|
|
8516
|
+
}
|
|
8517
|
+
return tickets;
|
|
8518
|
+
} catch (error) {
|
|
8519
|
+
return [];
|
|
8520
|
+
}
|
|
8521
|
+
}
|
|
8522
|
+
async _calculateChangedLinesFromPR(owner, repo, prNumber) {
|
|
8523
|
+
try {
|
|
8524
|
+
const diffRes = await this.githubSdk.getPrDiff({
|
|
8525
|
+
owner,
|
|
8526
|
+
repo,
|
|
8527
|
+
pull_number: prNumber
|
|
8528
|
+
});
|
|
8529
|
+
const diff = z21.string().parse(diffRes.data);
|
|
8530
|
+
let added = 0;
|
|
8531
|
+
let removed = 0;
|
|
8532
|
+
const lines = diff.split("\n");
|
|
8533
|
+
for (const line of lines) {
|
|
8534
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
8535
|
+
added++;
|
|
8536
|
+
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
8537
|
+
removed++;
|
|
8538
|
+
}
|
|
8539
|
+
}
|
|
8540
|
+
return { added, removed };
|
|
8541
|
+
} catch (error) {
|
|
8542
|
+
return { added: 0, removed: 0 };
|
|
8543
|
+
}
|
|
8544
|
+
}
|
|
8545
|
+
_calculateDiffLineAttributions(prDiff, commits) {
|
|
8546
|
+
const attributions = [];
|
|
8547
|
+
const prDiffLines = prDiff.split("\n");
|
|
8548
|
+
let currentFile = "";
|
|
8549
|
+
let currentLineNumber = 0;
|
|
8550
|
+
for (const line of prDiffLines) {
|
|
8551
|
+
if (line.startsWith("+++")) {
|
|
8552
|
+
const match = line.match(/^\+\+\+ b\/(.+)$/);
|
|
8553
|
+
currentFile = match?.[1] || "";
|
|
8554
|
+
currentLineNumber = 0;
|
|
8555
|
+
continue;
|
|
8556
|
+
}
|
|
8557
|
+
if (line.startsWith("@@")) {
|
|
8558
|
+
const match = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)/);
|
|
8559
|
+
if (match?.[1]) {
|
|
8560
|
+
currentLineNumber = parseInt(match[1], 10);
|
|
8561
|
+
}
|
|
8562
|
+
continue;
|
|
8563
|
+
}
|
|
8564
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
8565
|
+
const commitSha = this._findCommitForLine(
|
|
8566
|
+
currentFile,
|
|
8567
|
+
currentLineNumber,
|
|
8568
|
+
line.substring(1),
|
|
8569
|
+
// Remove the '+' prefix
|
|
8570
|
+
commits
|
|
8571
|
+
);
|
|
8572
|
+
if (commitSha && currentFile) {
|
|
8573
|
+
attributions.push({
|
|
8574
|
+
file: currentFile,
|
|
8575
|
+
line: currentLineNumber,
|
|
8576
|
+
commitSha
|
|
8577
|
+
});
|
|
8578
|
+
}
|
|
8579
|
+
currentLineNumber++;
|
|
8580
|
+
} else if (!line.startsWith("-")) {
|
|
8581
|
+
currentLineNumber++;
|
|
8582
|
+
}
|
|
8583
|
+
}
|
|
8584
|
+
return attributions;
|
|
8585
|
+
}
|
|
8586
|
+
_findCommitForLine(file, lineNumber, lineContent, commits) {
|
|
8587
|
+
const normalizedContent = lineContent.trim();
|
|
8588
|
+
for (let i = commits.length - 1; i >= 0; i--) {
|
|
8589
|
+
const commit = commits[i];
|
|
8590
|
+
if (!commit) {
|
|
8591
|
+
continue;
|
|
8592
|
+
}
|
|
8593
|
+
const commitLines = commit.diff.split("\n");
|
|
8594
|
+
let commitCurrentFile = "";
|
|
8595
|
+
for (const commitLine of commitLines) {
|
|
8596
|
+
if (commitLine.startsWith("+++")) {
|
|
8597
|
+
const match = commitLine.match(/^\+\+\+ b\/(.+)$/);
|
|
8598
|
+
commitCurrentFile = match?.[1] || "";
|
|
8599
|
+
continue;
|
|
8600
|
+
}
|
|
8601
|
+
if (commitLine.startsWith("@@")) {
|
|
8602
|
+
continue;
|
|
8603
|
+
}
|
|
8604
|
+
if (commitCurrentFile === file && commitLine.startsWith("+") && !commitLine.startsWith("+++")) {
|
|
8605
|
+
const commitLineContent = commitLine.substring(1).trim();
|
|
8606
|
+
if (commitLineContent === normalizedContent) {
|
|
8607
|
+
return commit.commitSha;
|
|
8608
|
+
}
|
|
8609
|
+
}
|
|
8610
|
+
}
|
|
8611
|
+
}
|
|
8612
|
+
for (let i = commits.length - 1; i >= 0; i--) {
|
|
8613
|
+
const commit = commits[i];
|
|
8614
|
+
if (!commit) {
|
|
8615
|
+
continue;
|
|
8616
|
+
}
|
|
8617
|
+
const addedLinesInFile = this._getAddedLinesFromCommit(commit, file);
|
|
8618
|
+
for (const { lineNum, content } of addedLinesInFile) {
|
|
8619
|
+
if (Math.abs(lineNum - lineNumber) <= 10 && this._contentSimilarity(content, normalizedContent) > 0.9) {
|
|
8620
|
+
return commit.commitSha;
|
|
8621
|
+
}
|
|
8622
|
+
}
|
|
8623
|
+
}
|
|
8624
|
+
const lastCommit = commits[commits.length - 1];
|
|
8625
|
+
return lastCommit ? lastCommit.commitSha : null;
|
|
8626
|
+
}
|
|
8627
|
+
_getAddedLinesFromCommit(commit, targetFile) {
|
|
8628
|
+
const addedLines = [];
|
|
8629
|
+
const commitLines = commit.diff.split("\n");
|
|
8630
|
+
let currentFile = "";
|
|
8631
|
+
let currentLineNumber = 0;
|
|
8632
|
+
for (const line of commitLines) {
|
|
8633
|
+
if (line.startsWith("+++")) {
|
|
8634
|
+
const match = line.match(/^\+\+\+ b\/(.+)$/);
|
|
8635
|
+
currentFile = match?.[1] || "";
|
|
8636
|
+
currentLineNumber = 0;
|
|
8637
|
+
continue;
|
|
8638
|
+
}
|
|
8639
|
+
if (line.startsWith("@@")) {
|
|
8640
|
+
const match = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)/);
|
|
8641
|
+
if (match?.[1]) {
|
|
8642
|
+
currentLineNumber = parseInt(match[1], 10);
|
|
8643
|
+
}
|
|
8644
|
+
continue;
|
|
8645
|
+
}
|
|
8646
|
+
if (currentFile === targetFile && line.startsWith("+") && !line.startsWith("+++")) {
|
|
8647
|
+
addedLines.push({
|
|
8648
|
+
lineNum: currentLineNumber,
|
|
8649
|
+
content: line.substring(1).trim()
|
|
8650
|
+
});
|
|
8651
|
+
currentLineNumber++;
|
|
8652
|
+
} else if (!line.startsWith("-")) {
|
|
8653
|
+
if (currentFile === targetFile) {
|
|
8654
|
+
currentLineNumber++;
|
|
8655
|
+
}
|
|
8656
|
+
}
|
|
8657
|
+
}
|
|
8658
|
+
return addedLines;
|
|
8659
|
+
}
|
|
8660
|
+
_contentSimilarity(content1, content2) {
|
|
8661
|
+
if (content1 === content2) {
|
|
8662
|
+
return 1;
|
|
8663
|
+
}
|
|
8664
|
+
const normalized1 = content1.replace(/\s+/g, " ");
|
|
8665
|
+
const normalized2 = content2.replace(/\s+/g, " ");
|
|
8666
|
+
if (normalized1 === normalized2) {
|
|
8667
|
+
return 0.95;
|
|
8668
|
+
}
|
|
8669
|
+
const longer = normalized1.length > normalized2.length ? normalized1 : normalized2;
|
|
8670
|
+
const shorter = normalized1.length > normalized2.length ? normalized2 : normalized1;
|
|
8671
|
+
if (longer.length === 0) {
|
|
8672
|
+
return 1;
|
|
8673
|
+
}
|
|
8674
|
+
if (longer.includes(shorter)) {
|
|
8675
|
+
return shorter.length / longer.length;
|
|
8676
|
+
}
|
|
8677
|
+
const set1 = new Set(normalized1.split(""));
|
|
8678
|
+
const set2 = new Set(normalized2.split(""));
|
|
8679
|
+
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
8680
|
+
return intersection.size / Math.max(set1.size, set2.size);
|
|
8681
|
+
}
|
|
8365
8682
|
};
|
|
8366
8683
|
|
|
8367
8684
|
// src/features/analysis/scm/gitlab/gitlab.ts
|
|
@@ -8930,6 +9247,12 @@ var GitlabSCMLib = class extends SCMLib {
|
|
|
8930
9247
|
async getCommitDiff(_commitSha) {
|
|
8931
9248
|
throw new Error("getCommitDiff not implemented for GitLab");
|
|
8932
9249
|
}
|
|
9250
|
+
async getSubmitRequestDiff(_submitRequestId) {
|
|
9251
|
+
throw new Error("getSubmitRequestDiff not implemented for GitLab");
|
|
9252
|
+
}
|
|
9253
|
+
async getSubmitRequests(_repoUrl) {
|
|
9254
|
+
throw new Error("getSubmitRequests not implemented for GitLab");
|
|
9255
|
+
}
|
|
8933
9256
|
};
|
|
8934
9257
|
|
|
8935
9258
|
// src/features/analysis/scm/scmFactory.ts
|
|
@@ -9037,6 +9360,28 @@ var StubSCMLib = class extends SCMLib {
|
|
|
9037
9360
|
message: void 0
|
|
9038
9361
|
};
|
|
9039
9362
|
}
|
|
9363
|
+
async getSubmitRequestDiff(_submitRequestId) {
|
|
9364
|
+
console.warn("getSubmitRequestDiff() returning stub diff");
|
|
9365
|
+
return {
|
|
9366
|
+
diff: "",
|
|
9367
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
9368
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
9369
|
+
submitRequestId: _submitRequestId,
|
|
9370
|
+
submitRequestNumber: parseInt(_submitRequestId) || 0,
|
|
9371
|
+
sourceBranch: "",
|
|
9372
|
+
targetBranch: "",
|
|
9373
|
+
authorName: void 0,
|
|
9374
|
+
authorEmail: void 0,
|
|
9375
|
+
title: void 0,
|
|
9376
|
+
description: void 0,
|
|
9377
|
+
commits: [],
|
|
9378
|
+
diffLines: []
|
|
9379
|
+
};
|
|
9380
|
+
}
|
|
9381
|
+
async getSubmitRequests(_repoUrl) {
|
|
9382
|
+
console.warn("getSubmitRequests() returning empty array");
|
|
9383
|
+
return [];
|
|
9384
|
+
}
|
|
9040
9385
|
};
|
|
9041
9386
|
|
|
9042
9387
|
// src/features/analysis/scm/scmFactory.ts
|
|
@@ -10176,7 +10521,10 @@ async function addFixCommentsForPr({
|
|
|
10176
10521
|
const {
|
|
10177
10522
|
vulnerabilityReport: {
|
|
10178
10523
|
projectId,
|
|
10179
|
-
project: {
|
|
10524
|
+
project: {
|
|
10525
|
+
organizationId,
|
|
10526
|
+
organization: { ghFixerNoFixComments }
|
|
10527
|
+
}
|
|
10180
10528
|
}
|
|
10181
10529
|
} = getAnalysisRes;
|
|
10182
10530
|
if (!getAnalysisRes.repo?.commitSha || !getAnalysisRes.repo.pullRequest) {
|
|
@@ -10205,74 +10553,76 @@ async function addFixCommentsForPr({
|
|
|
10205
10553
|
...deleteAllPreviousComments({ comments, scm }),
|
|
10206
10554
|
...deleteAllPreviousGeneralPrComments({ generalPrComments, scm })
|
|
10207
10555
|
]);
|
|
10208
|
-
await Promise.all(
|
|
10209
|
-
|
|
10210
|
-
(
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
}
|
|
10223
|
-
),
|
|
10224
|
-
...irrelevantVulnerabilityReportIssues.map(
|
|
10225
|
-
async (vulnerabilityReportIssue) => {
|
|
10226
|
-
let fpDescription = null;
|
|
10227
|
-
if (vulnerabilityReportIssue.fpId) {
|
|
10228
|
-
const fpRes = await gqlClient.getFalsePositive({
|
|
10229
|
-
fpId: vulnerabilityReportIssue.fpId
|
|
10556
|
+
await Promise.all(
|
|
10557
|
+
[
|
|
10558
|
+
...prVulenrabilities.vulnerabilityReportIssueCodeNodes.map(
|
|
10559
|
+
(vulnerabilityReportIssueCodeNode) => {
|
|
10560
|
+
return postFixComment({
|
|
10561
|
+
vulnerabilityReportIssueCodeNode,
|
|
10562
|
+
projectId,
|
|
10563
|
+
analysisId,
|
|
10564
|
+
organizationId,
|
|
10565
|
+
fixesById,
|
|
10566
|
+
scm,
|
|
10567
|
+
pullRequest,
|
|
10568
|
+
scanner,
|
|
10569
|
+
commitSha
|
|
10230
10570
|
});
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
|
|
10235
|
-
fpDescription =
|
|
10571
|
+
}
|
|
10572
|
+
),
|
|
10573
|
+
...irrelevantVulnerabilityReportIssues.map(
|
|
10574
|
+
async (vulnerabilityReportIssue) => {
|
|
10575
|
+
let fpDescription = null;
|
|
10576
|
+
if (vulnerabilityReportIssue.fpId) {
|
|
10577
|
+
const fpRes = await gqlClient.getFalsePositive({
|
|
10578
|
+
fpId: vulnerabilityReportIssue.fpId
|
|
10579
|
+
});
|
|
10580
|
+
const parsedFpRes = await FalsePositivePartsZ.parseAsync(
|
|
10581
|
+
fpRes?.getFalsePositive
|
|
10582
|
+
);
|
|
10583
|
+
const { description, contextString } = getParsedFalsePositiveMessage(parsedFpRes);
|
|
10584
|
+
fpDescription = contextString ? `${description}
|
|
10236
10585
|
|
|
10237
10586
|
${contextString}` : description;
|
|
10238
|
-
|
|
10239
|
-
|
|
10240
|
-
|
|
10241
|
-
|
|
10242
|
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10587
|
+
}
|
|
10588
|
+
return await Promise.all(
|
|
10589
|
+
vulnerabilityReportIssue.codeNodes.map(
|
|
10590
|
+
async (vulnerabilityReportIssueCodeNode) => {
|
|
10591
|
+
return await postIssueComment({
|
|
10592
|
+
vulnerabilityReportIssueCodeNode: {
|
|
10593
|
+
path: vulnerabilityReportIssueCodeNode.path,
|
|
10594
|
+
startLine: vulnerabilityReportIssueCodeNode.startLine,
|
|
10595
|
+
vulnerabilityReportIssue: {
|
|
10596
|
+
fixId: "",
|
|
10597
|
+
safeIssueType: vulnerabilityReportIssue.safeIssueType,
|
|
10598
|
+
vulnerabilityReportIssueTags: vulnerabilityReportIssue.vulnerabilityReportIssueTags,
|
|
10599
|
+
category: vulnerabilityReportIssue.category
|
|
10600
|
+
},
|
|
10601
|
+
vulnerabilityReportIssueId: vulnerabilityReportIssue.id
|
|
10251
10602
|
},
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10265
|
-
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
|
|
10275
|
-
]);
|
|
10603
|
+
projectId,
|
|
10604
|
+
analysisId,
|
|
10605
|
+
organizationId,
|
|
10606
|
+
fixesById,
|
|
10607
|
+
scm,
|
|
10608
|
+
pullRequest,
|
|
10609
|
+
scanner,
|
|
10610
|
+
commitSha,
|
|
10611
|
+
fpDescription
|
|
10612
|
+
});
|
|
10613
|
+
}
|
|
10614
|
+
)
|
|
10615
|
+
);
|
|
10616
|
+
}
|
|
10617
|
+
),
|
|
10618
|
+
!ghFixerNoFixComments && postAnalysisInsightComment({
|
|
10619
|
+
prVulenrabilities,
|
|
10620
|
+
pullRequest,
|
|
10621
|
+
scanner,
|
|
10622
|
+
scm
|
|
10623
|
+
})
|
|
10624
|
+
].filter(Boolean)
|
|
10625
|
+
);
|
|
10276
10626
|
}
|
|
10277
10627
|
|
|
10278
10628
|
// src/features/analysis/auto_pr_handler.ts
|
|
@@ -12637,6 +12987,8 @@ var VulnerabilityReportSchema = z31.object({
|
|
|
12637
12987
|
// GraphQL uses `any` type for timestamp
|
|
12638
12988
|
vendor: z31.string(),
|
|
12639
12989
|
// GraphQL generates as string, not enum
|
|
12990
|
+
projectId: z31.any().optional(),
|
|
12991
|
+
// GraphQL uses `any` type for UUID
|
|
12640
12992
|
project: ProjectSchema,
|
|
12641
12993
|
totalVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema,
|
|
12642
12994
|
notFixableVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema
|
|
@@ -13136,7 +13488,7 @@ var McpGQLClient = class {
|
|
|
13136
13488
|
const reportMetadata = {
|
|
13137
13489
|
id: reportData.id,
|
|
13138
13490
|
organizationId: reportData.vulnerabilityReport?.project?.organizationId,
|
|
13139
|
-
projectId: reportData.vulnerabilityReport?.
|
|
13491
|
+
projectId: reportData.vulnerabilityReport?.projectId
|
|
13140
13492
|
};
|
|
13141
13493
|
const { userFixes = [], fixes = [] } = reportData;
|
|
13142
13494
|
const fixMap = /* @__PURE__ */ new Map();
|
|
@@ -13353,6 +13705,7 @@ var McpGQLClient = class {
|
|
|
13353
13705
|
reportData: latestReport,
|
|
13354
13706
|
limit
|
|
13355
13707
|
});
|
|
13708
|
+
logDebug("[GraphQL] GetReportFixes response parsed", { fixes });
|
|
13356
13709
|
return {
|
|
13357
13710
|
fixes,
|
|
13358
13711
|
totalCount: res.fixReport?.[0]?.filteredFixesCount?.aggregate?.count || 0,
|