fix: dedupe sentinel report artifact findings
This commit is contained in:
@@ -336,8 +336,9 @@ function compactSentinelReportRawPayload(
|
||||
function mergeSentinelReportFindings(primary: readonly Record<string, unknown>[], artifact: readonly Record<string, unknown>[]): Record<string, unknown>[] {
|
||||
const merged: Record<string, unknown>[] = [];
|
||||
const seen = new Set<string>();
|
||||
const aliases = sentinelReportFindingIdentityAliases(primary);
|
||||
for (const item of [...primary, ...artifact]) {
|
||||
const id = sentinelReportFindingIdentity(item);
|
||||
const id = sentinelReportCanonicalFindingIdentity(item, aliases);
|
||||
const key = id ?? `${JSON.stringify(item).slice(0, 160)}:${stringAtNullable(item, "severity") ?? stringAtNullable(item, "level") ?? ""}`;
|
||||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
@@ -346,6 +347,48 @@ function mergeSentinelReportFindings(primary: readonly Record<string, unknown>[]
|
||||
return merged;
|
||||
}
|
||||
|
||||
function sentinelReportFindingIdentityAliases(items: readonly Record<string, unknown>[]): Map<string, string> {
|
||||
const aliases = new Map<string, string>();
|
||||
for (const item of items) {
|
||||
const canonical = sentinelReportFindingCanonicalCandidate(item) ?? sentinelReportFindingIdentity(item);
|
||||
if (canonical === null) continue;
|
||||
for (const candidate of sentinelReportFindingIdentityCandidates(item)) aliases.set(candidate, canonical);
|
||||
}
|
||||
return aliases;
|
||||
}
|
||||
|
||||
function sentinelReportCanonicalFindingIdentity(item: Record<string, unknown>, aliases: ReadonlyMap<string, string>): string | null {
|
||||
for (const candidate of sentinelReportFindingIdentityCandidates(item)) {
|
||||
const canonical = aliases.get(candidate);
|
||||
if (canonical !== undefined) return canonical;
|
||||
}
|
||||
return sentinelReportFindingCanonicalCandidate(item) ?? sentinelReportFindingIdentity(item);
|
||||
}
|
||||
|
||||
function sentinelReportFindingCanonicalCandidate(item: Record<string, unknown>): string | null {
|
||||
const check = record(item.check);
|
||||
return stringAtNullable(item, "checkCode")
|
||||
?? stringAtNullable(check, "code")
|
||||
?? stringAtNullable(item, "checkId")
|
||||
?? stringAtNullable(check, "id");
|
||||
}
|
||||
|
||||
function sentinelReportFindingIdentityCandidates(item: Record<string, unknown>): readonly string[] {
|
||||
const check = record(item.check);
|
||||
const candidates = [
|
||||
stringAtNullable(item, "finding_id"),
|
||||
stringAtNullable(item, "findingId"),
|
||||
stringAtNullable(item, "id"),
|
||||
stringAtNullable(item, "kind"),
|
||||
stringAtNullable(item, "code"),
|
||||
stringAtNullable(item, "checkId"),
|
||||
stringAtNullable(item, "checkCode"),
|
||||
stringAtNullable(check, "id"),
|
||||
stringAtNullable(check, "code"),
|
||||
];
|
||||
return [...new Set(candidates.filter((item): item is string => item !== null))];
|
||||
}
|
||||
|
||||
function sentinelReportFindingIdentity(item: Record<string, unknown>): string | null {
|
||||
return stringAtNullable(item, "finding_id")
|
||||
?? stringAtNullable(item, "findingId")
|
||||
|
||||
Reference in New Issue
Block a user