From 0da9bd80fb7e25b3a80e5cff3b48e292bdf46bb8 Mon Sep 17 00:00:00 2001 From: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com> Date: Wed, 2 Jul 2025 14:36:00 +0530 Subject: [PATCH] feat: add tool to detect new failed findings in a scan --- ui/lib/lighthouse/tools/findings.ts | 80 +++++++++++++++++++++++++++++ ui/lib/lighthouse/workflow.ts | 2 + 2 files changed, 82 insertions(+) diff --git a/ui/lib/lighthouse/tools/findings.ts b/ui/lib/lighthouse/tools/findings.ts index 8ef65f69e4..215c3fd2fe 100644 --- a/ui/lib/lighthouse/tools/findings.ts +++ b/ui/lib/lighthouse/tools/findings.ts @@ -1,4 +1,5 @@ import { tool } from "@langchain/core/tools"; +import { z } from "zod"; import { getMetadataInfo } from "@/actions/findings"; import { @@ -44,6 +45,85 @@ export const getLatestFindingsTool = tool( }, ); +// Function to get a summary of new and changed failed findings that appeared in a particular scan +export const getNewFailedFindingsSummary = async (scanId: string) => { + let allFindings: any[] = []; + let currentPage = 1; + let totalPages = 1; + const pageSize = 100; + + do { + const response = await getLighthouseFindings({ + page: currentPage, + pageSize: pageSize, + sort: "severity", + filters: { + "fields[findings]": "check_id,severity", + "filter[scan]": scanId, + "filter[status]": "FAIL", + "filter[muted]": "false", + "filter[delta__in]": "new,changed", + }, + }); + + if (response?.data) { + allFindings = allFindings.concat(response.data); + } + + if (currentPage === 1 && response?.meta?.pagination) { + totalPages = response.meta.pagination.pages; + } + + currentPage++; + } while (currentPage <= totalPages); + + const summary: Record< + string, + Record + > = {}; + + allFindings.forEach((finding) => { + const severity = finding.attributes.severity; + const checkId = finding.attributes.check_id; + const findingId = finding.id; + + // Initialize severity group if it doesn't exist + if (!summary[severity]) { + summary[severity] = {}; + } + + // Initialize check_id group if it doesn't exist + if (!summary[severity][checkId]) { + summary[severity][checkId] = { + count: 0, + finding_ids: [], + }; + } + + // Add finding to the appropriate group + summary[severity][checkId].count++; + summary[severity][checkId].finding_ids.push(findingId); + }); + + return summary; +}; + +export const getNewFailedFindingsSummaryTool = tool( + async ({ scanId }) => { + return await getNewFailedFindingsSummary(scanId); + }, + { + name: "getNewFailedFindingsSummary", + description: + "Fetches summary of new and changed failed findings that appeared in a particular scan. Summary includes count of findings by severity, check_id and finding_ids.", + schema: z.object({ + scanId: z + .string() + .describe("The UUID of the scan to fetch failed findings summary for."), + }), + }, +); + export const getMetadataInfoTool = tool( async ({ query, sort, filters }) => { return await getMetadataInfo({ query, sort, filters }); diff --git a/ui/lib/lighthouse/workflow.ts b/ui/lib/lighthouse/workflow.ts index bd61bc897c..36cef8d07d 100644 --- a/ui/lib/lighthouse/workflow.ts +++ b/ui/lib/lighthouse/workflow.ts @@ -26,6 +26,7 @@ import { getFindingsTool, getLatestFindingsTool, getMetadataInfoTool, + getNewFailedFindingsSummaryTool, } from "@/lib/lighthouse/tools/findings"; import { getFindingsBySeverityTool, @@ -104,6 +105,7 @@ export async function initLighthouseWorkflow() { getFindingsTool, getLatestFindingsTool, getMetadataInfoTool, + getNewFailedFindingsSummaryTool, getProviderChecksTool, getProviderCheckDetailsTool, ],