From c3e50e360009e26f28559ebd616f79f1ba468c0a Mon Sep 17 00:00:00 2001 From: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com> Date: Thu, 7 Aug 2025 11:42:07 +0530 Subject: [PATCH] fix: move recommendation generator to supervisor agent --- ui/app/(prowler)/page.tsx | 4 -- ui/components/lighthouse/banner.tsx | 38 ++++++---- ui/lib/lighthouse/cache.ts | 2 +- ui/lib/lighthouse/recommendations.ts | 103 ++++++++++----------------- ui/lib/lighthouse/tools/overview.ts | 2 +- 5 files changed, 66 insertions(+), 83 deletions(-) diff --git a/ui/app/(prowler)/page.tsx b/ui/app/(prowler)/page.tsx index 5a8c694c51..c4513404d0 100644 --- a/ui/app/(prowler)/page.tsx +++ b/ui/app/(prowler)/page.tsx @@ -35,10 +35,6 @@ export default function Home({ - {/* - - */} -
}> diff --git a/ui/components/lighthouse/banner.tsx b/ui/components/lighthouse/banner.tsx index 5fdcaead63..9c07c6e655 100644 --- a/ui/components/lighthouse/banner.tsx +++ b/ui/components/lighthouse/banner.tsx @@ -27,9 +27,16 @@ const renderBanner = ({ message, href, gradient }: BannerConfig) => ( ); +// Triggers a background job to process the scans and generate recommendations +// Immediately returns a banner with different content +// If Lighthouse is not configured, returns a banner with a different message +// If cache available, returns a banner with the cached recommendation +// If recommendation is being processed, returns a banner with a different message export const LighthouseBanner = async () => { try { + // Triggers a background job to process the scans and generate recommendations await initializeTenantCache(); + const lighthouseConfig = await getLighthouseConfig(); if (!lighthouseConfig) { @@ -41,6 +48,18 @@ export const LighthouseBanner = async () => { }); } + // Check if recommendation is being processed + const isProcessing = await CacheService.isRecommendationProcessing(); + + if (isProcessing) { + return renderBanner({ + message: "Lighthouse is reviewing your findings for insights", + href: "", + gradient: + "bg-gradient-to-r from-orange-500 to-yellow-500 hover:from-orange-600 hover:to-yellow-600 focus:ring-orange-500/50 dark:from-orange-600 dark:to-yellow-600 dark:hover:from-orange-700 dark:hover:to-yellow-700 dark:focus:ring-orange-400/50", + }); + } + // Check if recommendation exists const cachedRecommendations = await CacheService.getRecommendations(); @@ -57,20 +76,13 @@ export const LighthouseBanner = async () => { }); } - // Check if recommendation is being processed - const isProcessing = await CacheService.isRecommendationProcessing(); - - if (isProcessing) { - return renderBanner({ - message: "Lighthouse is reviewing your findings for insights", - href: "", - gradient: - "bg-gradient-to-r from-orange-500 to-yellow-500 hover:from-orange-600 hover:to-yellow-600 focus:ring-orange-500/50 dark:from-orange-600 dark:to-yellow-600 dark:hover:from-orange-700 dark:hover:to-yellow-700 dark:focus:ring-orange-400/50", - }); - } - // Lighthouse configured but no recommendation and not processing - don't show banner - return null; + return renderBanner({ + message: "Use Lighthouse to review your findings and gain insights", + href: "/lighthouse", + gradient: + "bg-gradient-to-r from-green-500 to-blue-500 hover:from-green-600 hover:to-blue-600 focus:ring-green-500/50 dark:from-green-600 dark:to-blue-600 dark:hover:from-green-700 dark:hover:to-blue-700 dark:focus:ring-green-400/50", + }); } catch (error) { console.error("Error getting banner state:", error); return null; diff --git a/ui/lib/lighthouse/cache.ts b/ui/lib/lighthouse/cache.ts index 071ddbf702..5b3fdac531 100644 --- a/ui/lib/lighthouse/cache.ts +++ b/ui/lib/lighthouse/cache.ts @@ -388,7 +388,7 @@ export async function initializeTenantCache(): Promise<{ scanSummary?: string; }> { try { - // Quick pre-check: Do we need to process anything? + // Check if there are any scans in the last 24h const currentScanIds = await getCompletedScansLast24h(); if (currentScanIds.length === 0) { diff --git a/ui/lib/lighthouse/recommendations.ts b/ui/lib/lighthouse/recommendations.ts index d8186d6c3e..1493227460 100644 --- a/ui/lib/lighthouse/recommendations.ts +++ b/ui/lib/lighthouse/recommendations.ts @@ -5,9 +5,7 @@ import { getAIKey, getLighthouseConfig } from "@/actions/lighthouse/lighthouse"; import { type SuggestedAction } from "./suggested-actions"; import { initLighthouseWorkflow } from "./workflow"; -export const generateDetailedRecommendation = async ( - scanSummary: string, -): Promise => { +export const generateDetailedRecommendation = async (): Promise => { try { const apiKey = await getAIKey(); if (!apiKey) { @@ -19,60 +17,47 @@ export const generateDetailedRecommendation = async ( return ""; } - const config = lighthouseConfig.attributes; - const businessContext = config.business_context || ""; + const workflow = await initLighthouseWorkflow(); + const response = await workflow.invoke({ + messages: [ + { + role: "user", + content: `Create focused and actionable recommendations to Security Engineering Manager based on findings from all recent completed scans. - const llm = new ChatOpenAI({ - model: config.model || "gpt-4o", - temperature: config.temperature || 0, - maxTokens: 1500, - apiKey: apiKey, +Your output should include both an overview of recent scans and your analysis about the findings. Your analysis should include the most urgent bug that needs to be fixed first (even if there are multiple bugs with different severities). + +Your output should contain the following: +- Overview of the recent scans and findings +- Comprehensive analysis of finding/pattern that users need to fix immediately + +When you're talking about any issue, be clear. For example: + +- When talking about findings, give the details of resources, account IDs, etc instead of just providing UUIDs of findings, resources, etc. +- When giving issue description, convey what exactly is the problem and the reason you think why it should be fixed first. +- When finding patterns, convey if users must focus on a particular bug class or particular cloud service or they must focus on a particular finding to improve their cloud security posture. +- When mentioning the affected resources, try to give the names of resources and account IDs instead of just providing UUIDs of findings, resources, etc. +- When giving business impact, tell the actual security risks of findings and potential consequences (possible bruteforce attacks on resources, compliance violation, etc) +- When giving remediation steps, give clear step-by-step instructions and any gotcha's they need to check before fix (if applicable). +- Be specific with numbers (e.g., "affects 12 S3 buckets", "resolves 15 findings"). Focus on actionable guidance that will have the biggest security improvement. + +Guidelines for checking findings: +- Go by the severity: critical, high, medium, low +- When fetching findings, order by severity +- Ignore muted findings + +Guidelines for writing the output: +- Use a formal yet casual tone. +- Don't make it look like a report. The output is read by humans. +- The output need not contain subheadings like issue description, affected resources, etc. +- First, give a few sentence overview about the recent scans and findings, then dig deeper into the critical top findings that user must focus on. +- Don't burden the user with too many findings. Evaluate the findings and tell them what they should focus on.`, + }, + ], }); - let systemPrompt = `You are a cloud security analyst providing focused, actionable recommendations. - -IMPORTANT: Focus on ONE of these high-impact opportunities: -1. The most CRITICAL finding that needs immediate attention -2. A pattern where fixing one check ID resolves many findings (e.g., "Fix aws_s3_bucket_public_access_block to resolve 15 findings") -3. The issue with highest business impact - -Your response should be a comprehensive analysis of this ONE focus area including: - -**Issue Description:** -- What exactly is the problem -- Why it's critical or high-impact -- How many findings it affects - -**Affected Resources:** -- Specific resources, services, or configurations involved -- Number of affected resources - -**Business Impact:** -- Security risks and potential consequences -- Compliance violations (mention specific frameworks if applicable) -- Operational impact - -**Remediation Steps:** -- Clear, step-by-step instructions -- Specific commands or configuration changes where applicable -- Expected outcome after fix - -Be specific with numbers (e.g., "affects 12 S3 buckets", "resolves 15 findings"). Focus on actionable guidance that will have the biggest security improvement.`; - - if (businessContext) { - systemPrompt += `\n\nBUSINESS CONTEXT: ${businessContext}`; - } - - systemPrompt += `\n\nSecurity Scan Summary:\n${scanSummary}`; - - const response = await llm.invoke([ - { - role: "system", - content: systemPrompt, - }, - ]); - - return response.content.toString().trim(); + const lastMessage = + response.messages[response.messages.length - 1]?.content?.toString?.(); + return lastMessage; } catch (error) { console.error("Error generating detailed recommendation:", error); return ""; @@ -138,16 +123,6 @@ ${detailedRecommendation}`; } }; -// Legacy function for backward compatibility -export const generateRecommendation = async ( - scanSummary: string, -): Promise => { - const detailed = await generateDetailedRecommendation(scanSummary); - if (!detailed) return ""; - - return await generateBannerFromDetailed(detailed); -}; - export const generateQuestionAnswers = async ( questions: SuggestedAction[], ): Promise> => { diff --git a/ui/lib/lighthouse/tools/overview.ts b/ui/lib/lighthouse/tools/overview.ts index 8087648aef..bde39ecb8e 100644 --- a/ui/lib/lighthouse/tools/overview.ts +++ b/ui/lib/lighthouse/tools/overview.ts @@ -42,7 +42,7 @@ export const getFindingsBySeverityTool = tool( { name: "getFindingsBySeverity", description: - "Retrieves an aggregated summary of findings grouped by severity levels, such as low, medium, high, and critical. The response includes the total count of findings for each severity, considering only the latest scans for each provider. Additional filters can be applied to narrow down results by region, provider type, or other attributes.", + "Retrieves an aggregated summary of all findings (including passed and failed) grouped by severity levels, such as low, medium, high, and critical. The response includes the total count of findings for each severity, considering only the latest scans for each provider. Additional filters can be applied to narrow down results by region, provider type, or other attributes. Note: This endpoint doesn't allow filtering or ordering by status, it only provides a summary of all detected findings including passed, failed and muted.", schema: getFindingsBySeveritySchema, }, );