mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 13:01:56 +00:00
feat: Add resource agent to supervisor (#8509)
Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
bb07cf9147
commit
efdeb431ba
+2
-1
@@ -8,6 +8,7 @@ All notable changes to the **Prowler UI** are documented in this file.
|
||||
|
||||
- `Cloud Provider` type filter to providers page [(#8473)](https://github.com/prowler-cloud/prowler/pull/8473)
|
||||
- New menu item under Configuration section for quick access to the Mutelist [(#8444)](https://github.com/prowler-cloud/prowler/pull/8444)
|
||||
- Resource agent to Lighthouse for querying resource information [(#8509)](https://github.com/prowler-cloud/prowler/pull/8509)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
@@ -15,6 +16,7 @@ All notable changes to the **Prowler UI** are documented in this file.
|
||||
- Provider connection filter now shows "Connected/Disconnected" instead of "true/false" for better UX [(#8520)](https://github.com/prowler-cloud/prowler/pull/8520)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- DataTable column headers set to single-line [(#8480)](https://github.com/prowler-cloud/prowler/pull/8480)
|
||||
|
||||
### ❌ Removed
|
||||
@@ -29,7 +31,6 @@ All notable changes to the **Prowler UI** are documented in this file.
|
||||
- `GitHub` submenu to High Risk Findings [(#8488)](https://github.com/prowler-cloud/prowler/pull/8488)
|
||||
- Improved Overview chart `Findings by Severity` spacing [(#8491)](https://github.com/prowler-cloud/prowler/pull/8491)
|
||||
|
||||
|
||||
## [1.10.0] (Prowler v5.10.0)
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import { apiBaseUrl, getAuthHeaders, parseStringify } from "@/lib/helper";
|
||||
|
||||
export async function getLighthouseResources(
|
||||
page: number = 1,
|
||||
query: string = "",
|
||||
sort: string = "",
|
||||
filters: any = {},
|
||||
fields: string[] = [],
|
||||
) {
|
||||
export async function getLighthouseResources({
|
||||
page = 1,
|
||||
query = "",
|
||||
sort = "",
|
||||
filters = {},
|
||||
fields = [],
|
||||
}: {
|
||||
page?: number;
|
||||
query?: string;
|
||||
sort?: string;
|
||||
filters?: any;
|
||||
fields?: string[];
|
||||
}) {
|
||||
const headers = await getAuthHeaders({ contentType: false });
|
||||
|
||||
const url = new URL(`${apiBaseUrl}/resources`);
|
||||
@@ -29,7 +35,7 @@ export async function getLighthouseResources(
|
||||
|
||||
if (filters) {
|
||||
for (const [key, value] of Object.entries(filters)) {
|
||||
url.searchParams.append(`filter[${key}]`, value as string);
|
||||
url.searchParams.append(`${key}`, value as string);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,11 +52,67 @@ export async function getLighthouseResources(
|
||||
}
|
||||
}
|
||||
|
||||
export async function getLighthouseResourceById(
|
||||
id: string,
|
||||
fields: string[] = [],
|
||||
include: string[] = [],
|
||||
) {
|
||||
export async function getLighthouseLatestResources({
|
||||
page = 1,
|
||||
query = "",
|
||||
sort = "",
|
||||
filters = {},
|
||||
fields = [],
|
||||
}: {
|
||||
page?: number;
|
||||
query?: string;
|
||||
sort?: string;
|
||||
filters?: any;
|
||||
fields?: string[];
|
||||
}) {
|
||||
const headers = await getAuthHeaders({ contentType: false });
|
||||
|
||||
const url = new URL(`${apiBaseUrl}/resources/latest`);
|
||||
|
||||
if (page) {
|
||||
url.searchParams.append("page[number]", page.toString());
|
||||
}
|
||||
|
||||
if (sort) {
|
||||
url.searchParams.append("sort", sort);
|
||||
}
|
||||
|
||||
if (query) {
|
||||
url.searchParams.append("filter[search]", query);
|
||||
}
|
||||
|
||||
if (fields.length > 0) {
|
||||
url.searchParams.append("fields[resources]", fields.join(","));
|
||||
}
|
||||
|
||||
if (filters) {
|
||||
for (const [key, value] of Object.entries(filters)) {
|
||||
url.searchParams.append(`${key}`, value as string);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(url.toString(), {
|
||||
headers,
|
||||
});
|
||||
const data = await response.json();
|
||||
const parsedData = parseStringify(data);
|
||||
return parsedData;
|
||||
} catch (error) {
|
||||
console.error("Error fetching resources:", error);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getLighthouseResourceById({
|
||||
id,
|
||||
fields = [],
|
||||
include = [],
|
||||
}: {
|
||||
id: string;
|
||||
fields?: string[];
|
||||
include?: string[];
|
||||
}) {
|
||||
const headers = await getAuthHeaders({ contentType: false });
|
||||
const url = new URL(`${apiBaseUrl}/resources/${id}`);
|
||||
|
||||
|
||||
@@ -136,6 +136,11 @@ You operate in an agent loop, iterating through these steps:
|
||||
- Fetches available user roles in Prowler
|
||||
- Can get detailed information about the role
|
||||
|
||||
### resources_agent
|
||||
|
||||
- Fetches information about resources found during Prowler scans
|
||||
- Can get detailed information about a specific resource
|
||||
|
||||
## Interacting with Agents
|
||||
|
||||
- Don't invoke agents if you have the necessary information in your prompt.
|
||||
@@ -469,11 +474,39 @@ const rolesAgentPrompt = `You are Prowler's Roles Agent, specializing in role an
|
||||
- Mentioning all keys in the function call is mandatory. Don't skip any keys.
|
||||
- Don't add empty filters in the function call.`;
|
||||
|
||||
const resourcesAgentPrompt = `You are Prowler's Resource Agent, specializing in fetching resource information within Prowler.
|
||||
|
||||
## Available Tools
|
||||
|
||||
- getResourcesTool: List available resource with filtering options
|
||||
- getResourceTool: Get detailed information about a specific resource by its UUID
|
||||
- getLatestResourcesTool: List available resources from the latest scans across all providers without scan UUID
|
||||
|
||||
## Response Guidelines
|
||||
|
||||
- Keep the response concise
|
||||
- Only share information relevant to the query
|
||||
- Answer directly without unnecessary introductions or conclusions
|
||||
- Ensure all responses are based on tools' output and information available in the prompt
|
||||
|
||||
## Additional Guidelines
|
||||
|
||||
- Focus only on resource-related information
|
||||
- Format resource IDs, permissions, and descriptions consistently
|
||||
- When user asks for resources without a specific scan UUID, use getLatestResourcesTool tool to fetch the resources
|
||||
- To get the resource UUID, use getResourcesTool if scan UUID is present. If scan UUID is not present, use getLatestResourcesTool.
|
||||
|
||||
## Tool Calling Guidelines
|
||||
|
||||
- Mentioning all keys in the function call is mandatory. Don't skip any keys.
|
||||
- Don't add empty filters in the function call.`;
|
||||
|
||||
export {
|
||||
complianceAgentPrompt,
|
||||
findingsAgentPrompt,
|
||||
overviewAgentPrompt,
|
||||
providerAgentPrompt,
|
||||
resourcesAgentPrompt,
|
||||
rolesAgentPrompt,
|
||||
scansAgentPrompt,
|
||||
supervisorPrompt,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { tool } from "@langchain/core/tools";
|
||||
|
||||
import {
|
||||
getLighthouseLatestResources,
|
||||
getLighthouseResourceById,
|
||||
getLighthouseResources,
|
||||
} from "@/actions/lighthouse/resources";
|
||||
@@ -8,22 +9,42 @@ import { getResourceSchema, getResourcesSchema } from "@/types/lighthouse";
|
||||
|
||||
export const getResourcesTool = tool(
|
||||
async ({ page, query, sort, filters, fields }) => {
|
||||
return await getLighthouseResources(page, query, sort, filters, fields);
|
||||
return await getLighthouseResources({ page, query, sort, filters, fields });
|
||||
},
|
||||
{
|
||||
name: "getResources",
|
||||
description: "Fetches all resource information",
|
||||
description:
|
||||
"Retrieve a list of all resources found during scans with options for filtering by various criteria. Mandatory to pass in scan UUID.",
|
||||
schema: getResourcesSchema,
|
||||
},
|
||||
);
|
||||
|
||||
export const getResourceTool = tool(
|
||||
async ({ id, fields, include }) => {
|
||||
return await getLighthouseResourceById(id, fields, include);
|
||||
return await getLighthouseResourceById({ id, fields, include });
|
||||
},
|
||||
{
|
||||
name: "getResource",
|
||||
description: "Fetches information about a resource by its UUID.",
|
||||
description:
|
||||
"Fetch detailed information about a specific resource by their Prowler assigned UUID. A Resource is an object that is discovered by Prowler. It can be anything from a single host to a whole VPC.",
|
||||
schema: getResourceSchema,
|
||||
},
|
||||
);
|
||||
|
||||
export const getLatestResourcesTool = tool(
|
||||
async ({ page, query, sort, filters, fields }) => {
|
||||
return await getLighthouseLatestResources({
|
||||
page,
|
||||
query,
|
||||
sort,
|
||||
filters,
|
||||
fields,
|
||||
});
|
||||
},
|
||||
{
|
||||
name: "getLatestResources",
|
||||
description:
|
||||
"Retrieve a list of the latest resources from the latest scans across all providers with options for filtering by various criteria.",
|
||||
schema: getResourcesSchema, // Schema is same as getResourcesSchema
|
||||
},
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
findingsAgentPrompt,
|
||||
overviewAgentPrompt,
|
||||
providerAgentPrompt,
|
||||
resourcesAgentPrompt,
|
||||
rolesAgentPrompt,
|
||||
scansAgentPrompt,
|
||||
supervisorPrompt,
|
||||
@@ -35,6 +36,11 @@ import {
|
||||
getProvidersTool,
|
||||
getProviderTool,
|
||||
} from "@/lib/lighthouse/tools/providers";
|
||||
import {
|
||||
getLatestResourcesTool,
|
||||
getResourcesTool,
|
||||
getResourceTool,
|
||||
} from "@/lib/lighthouse/tools/resources";
|
||||
import { getRolesTool, getRoleTool } from "@/lib/lighthouse/tools/roles";
|
||||
import { getScansTool, getScanTool } from "@/lib/lighthouse/tools/scans";
|
||||
import {
|
||||
@@ -127,6 +133,13 @@ export async function initLighthouseWorkflow() {
|
||||
prompt: rolesAgentPrompt,
|
||||
});
|
||||
|
||||
const resourcesAgent = createReactAgent({
|
||||
llm: llm,
|
||||
tools: [getResourceTool, getResourcesTool, getLatestResourcesTool],
|
||||
name: "resources_agent",
|
||||
prompt: resourcesAgentPrompt,
|
||||
});
|
||||
|
||||
const agents = [
|
||||
userInfoAgent,
|
||||
providerAgent,
|
||||
@@ -135,6 +148,7 @@ export async function initLighthouseWorkflow() {
|
||||
complianceAgent,
|
||||
findingsAgent,
|
||||
rolesAgent,
|
||||
resourcesAgent,
|
||||
];
|
||||
|
||||
// Create supervisor workflow
|
||||
|
||||
@@ -11,6 +11,7 @@ const resourceFieldsEnum = z.enum([
|
||||
"tags",
|
||||
"provider",
|
||||
"findings",
|
||||
"failed_findings_count",
|
||||
"url",
|
||||
"type",
|
||||
]);
|
||||
@@ -129,6 +130,10 @@ export const getResourcesSchema = z.object({
|
||||
.optional()
|
||||
.describe("Filter by multiple tags separated by commas."),
|
||||
"filter[type]": z.string().optional().describe("Filter by type."),
|
||||
"filter[type__icontains]": z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Filter by substring."),
|
||||
"filter[type__in]": z
|
||||
.string()
|
||||
.optional()
|
||||
@@ -138,18 +143,15 @@ export const getResourcesSchema = z.object({
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Filter by substring."),
|
||||
"filter[updated_at]": z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("The uid to filter by."),
|
||||
"filter[updated_at]": z.string().optional().describe("Filter by date."),
|
||||
"filter[updated_at__gte]": z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("The uid to filter by."),
|
||||
.describe("Filter by date greater than or equal to."),
|
||||
"filter[updated_at__lte]": z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("The uid to filter by."),
|
||||
.describe("Filter by date less than or equal to."),
|
||||
})
|
||||
.optional()
|
||||
.describe("The filters to apply to the resources."),
|
||||
|
||||
Reference in New Issue
Block a user