import { z } from 'zod'; import { type APIClient, APIResponseSchema } from '@agentuity/api'; import { MalwareCheckError } from './util.ts'; export const PackageRefSchema = z .object({ name: z.string().describe('Package name (e.g., lodash, express).'), version: z.string().describe('Package version (e.g., 4.17.21).'), }) .describe('Reference to an npm package with name and version.'); export type PackageRef = z.infer; export const MalwareFindingSchema = z .object({ name: z.string().describe('Name of the flagged package.'), version: z.string().describe('Version of the flagged package.'), reason: z.string().describe('Reason why the package was flagged as potentially malicious.'), }) .describe('A malware detection finding for a specific package.'); export type MalwareFinding = z.infer; export const MalwareCheckSummarySchema = z .object({ scanned: z.number().describe('Total number of packages scanned.'), flagged: z.number().describe('Number of packages flagged as potentially malicious.'), }) .describe('Summary of a malware check scan.'); export const MalwareCheckListMetadataSchema = z .object({ fetchedAt: z.string().describe('ISO 8601 timestamp when the malware list was last fetched.'), count: z.number().describe('Number of entries in the malware list.'), }) .describe('Metadata about the malware detection list used for scanning.'); export const MalwareCheckResultSchema = z .object({ action: z .enum(['allow', 'block']) .describe('Action to take based on the scan results (allow or block deployment).'), summary: MalwareCheckSummarySchema.describe('Summary of the malware check scan.'), findings: z.array(MalwareFindingSchema).describe('List of malware detection findings.'), list: MalwareCheckListMetadataSchema.optional().describe( 'Metadata about the malware list used, if available.' ), error: z .string() .optional() .describe('Error message if the malware check encountered an issue.'), }) .describe('Result of a malware check for a deployment.'); export const MalwareCheckResponseSchema = APIResponseSchema(MalwareCheckResultSchema); export type MalwareCheckResult = z.infer; export async function projectDeploymentMalwareCheck( client: APIClient, deploymentId: string, packages: PackageRef[], signal?: AbortSignal ): Promise { const resp = await client.request>( 'POST', `/security/${encodeURIComponent(deploymentId)}/malware-check`, MalwareCheckResponseSchema, { ecosystem: 'npm', packages, }, undefined, signal ); if (!resp.success) { throw new MalwareCheckError({ message: resp.message || 'Malware check request failed', deploymentId, }); } return resp.data; }