import { isAbsolute } from "node:path"; import { z } from "zod"; import { javascriptApplicationGraphSchema } from "./javascriptApplicationGraph.js"; import { javaScriptSemanticGraphSchema } from "./javascriptSemanticGraph.js"; const MAX_GRAPH_NODES = 100_000; const MAX_GRAPH_EDGES = 200_000; const countSchema = z.number().int().min(0).max(Number.MAX_SAFE_INTEGER); const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u); /** Default hard bounds for one local JavaScript application analysis. */ export const JAVASCRIPT_APPLICATION_ANALYSIS_DEFAULT_LIMITS = { max_entries: 8_000, max_total_artifact_bytes: 512 * 1_024 * 1_024, max_artifact_entry_bytes: 128 * 1_024 * 1_024, max_compression_ratio: 1_000, max_depth: 64, max_path_bytes: 4_096, max_text_files: 5_000, max_total_text_bytes: 128 * 1_024 * 1_024, max_text_file_bytes: 8 * 1_024 * 1_024, max_ast_nodes: 2_000_000, max_findings: 8_000, max_modules: 20_000, max_source_map_sources: 5_000, max_parse_milliseconds: 30_000, } as const; /** Combined artifact, text, AST, and graph projection bounds. */ export const javascriptApplicationAnalysisLimitsSchema = z .strictObject({ max_entries: z.number().int().min(1).max(1_000_000).default(8_000), max_total_artifact_bytes: z .number() .int() .min(1) .max(Number.MAX_SAFE_INTEGER) .default(512 * 1_024 * 1_024), max_artifact_entry_bytes: z .number() .int() .min(1) .max(Number.MAX_SAFE_INTEGER) .default(128 * 1_024 * 1_024), max_compression_ratio: z.number().min(1).max(100_000).default(1_000), max_depth: z.number().int().min(1).max(100).default(64), max_path_bytes: z.number().int().min(1).max(65_535).default(4_096), max_text_files: z.number().int().min(1).max(100_000).default(5_000), max_total_text_bytes: z .number() .int() .min(1) .max(512 * 1_024 * 1_024) .default(128 * 1_024 * 1_024), max_text_file_bytes: z .number() .int() .min(1) .max(64 * 1_024 * 1_024) .default(8 * 1_024 * 1_024), max_ast_nodes: z.number().int().min(1).max(20_000_000).default(2_000_000), max_findings: z.number().int().min(1).max(200_000).default(8_000), max_modules: z.number().int().min(1).max(100_000).default(20_000), max_source_map_sources: z.number().int().min(1).max(100_000).default(5_000), max_parse_milliseconds: z .number() .int() .min(1) .max(300_000) .default(30_000), }) .superRefine((limits, context) => { const projectedNodes = 7 * limits.max_entries + 2 * limits.max_findings + limits.max_modules + limits.max_source_map_sources + 1; if (projectedNodes > MAX_GRAPH_NODES) context.addIssue({ code: "custom", path: ["max_entries"], message: "Combined application-analysis limits can exceed the 100000-node graph contract", }); const projectedEdges = 9 * limits.max_entries + 6 * limits.max_findings + limits.max_modules + limits.max_source_map_sources; if (projectedEdges > MAX_GRAPH_EDGES) context.addIssue({ code: "custom", path: ["max_entries"], message: "Combined application-analysis limits can exceed the 200000-edge graph contract", }); }); /** Public target-free request for bounded static JavaScript application analysis. */ export const analyzeJavaScriptApplicationInputSchema = z.strictObject({ input_path: z .string() .min(1) .max(16_384) .refine(isAbsolute, "JavaScript application input path must be absolute"), format: z.enum(["auto", "asar", "directory"]).default("auto"), approved: z.literal(true), source_map_read_approved: z.boolean().default(false), limits: javascriptApplicationAnalysisLimitsSchema.default( JAVASCRIPT_APPLICATION_ANALYSIS_DEFAULT_LIMITS, ), }); /** Compact counts for the high-level Electron architecture/security surface. */ const electronBoundarySummarySchema = z.strictObject({ browser_windows: countSchema, explicit_web_preferences: countSchema, preload_entrypoints: countSchema, context_bridge_apis: countSchema, exposed_api_members: countSchema, ipc: z.strictObject({ operations: countSchema, literal_channels: countSchema, dynamic_channel_operations: countSchema, renderer_transmissions: countSchema, renderer_listeners: countSchema, main_handlers: countSchema, paired_renderer_transmissions: countSchema, ambiguous_renderer_transmissions: countSchema, unpaired_literal_renderer_transmissions: countSchema, }), sender_validation_observations: countSchema, utility_processes: countSchema, resolved_utility_entrypoints: countSchema, native_addon_bindings: countSchema, resolved_native_addon_bindings: countSchema, }); const reconstructionStatisticsSchema = z.strictObject({ relevant_files: countSchema, nested_asar_containers: countSchema, text_files_selected: countSchema, text_bytes_read: countSchema, omitted_text_files: countSchema, limit_omitted_text_files: countSchema, policy_filtered_text_files: countSchema, invalid_utf8_files: countSchema, parsed_javascript_files: countSchema, visited_ast_nodes: countSchema, findings: countSchema, modules: countSchema, parse_failures: countSchema, truncated_scopes: countSchema, }); /** Legacy structural JavaScript application analysis result. */ export const javaScriptApplicationAnalysisResultV1Schema = z.strictObject({ schema_version: z.literal(1), input_path: z.string().min(1).max(16_384), format: z.enum(["asar", "directory"]), root_artifact_sha256: digestSchema, inventory_manifest_id: z.string().regex(/^agm_[a-f0-9]{64}$/u), inventory_graph_sha256: digestSchema, graph: javascriptApplicationGraphSchema, summary: electronBoundarySummarySchema, statistics: reconstructionStatisticsSchema, limitations: z.array(z.string().min(1).max(4_096)).max(1_000), }); /** JavaScript application analysis with an authenticated semantic companion. */ export const javaScriptApplicationAnalysisResultV2Schema = javaScriptApplicationAnalysisResultV1Schema .extend({ schema_version: z.literal(2), semantic_graph: javaScriptSemanticGraphSchema, }) .superRefine((result, context) => { if (result.semantic_graph.application_graph_id !== result.graph.graph_id) context.addIssue({ code: "custom", path: ["semantic_graph", "application_graph_id"], message: "Semantic graph must commit the containing application graph", }); if ( result.semantic_graph.root_artifact_sha256 !== result.root_artifact_sha256 ) context.addIssue({ code: "custom", path: ["semantic_graph", "root_artifact_sha256"], message: "Semantic graph must commit the containing root artifact", }); const applicationNodeIds = new Set( result.graph.nodes.map(({ node_id }) => node_id), ); for (const [nodeIndex, node] of result.semantic_graph.nodes.entries()) for (const [ identifierIndex, identifier, ] of node.application_node_ids.entries()) if (!applicationNodeIds.has(identifier)) context.addIssue({ code: "custom", path: [ "semantic_graph", "nodes", nodeIndex, "application_node_ids", identifierIndex, ], message: "Semantic node references an absent application node", }); }); /** Strict versioned high-level result returned inside Evidence v2. */ export const javascriptApplicationAnalysisResultSchema = z.discriminatedUnion( "schema_version", [ javaScriptApplicationAnalysisResultV1Schema, javaScriptApplicationAnalysisResultV2Schema, ], ); /** Parsed public JavaScript application analysis request. */ export type AnalyzeJavaScriptApplicationInput = z.infer< typeof analyzeJavaScriptApplicationInputSchema >; /** Validated high-level JavaScript application analysis result. */ export type JavaScriptApplicationAnalysisResult = z.infer< typeof javascriptApplicationAnalysisResultSchema >; /** Validated high-level Electron boundary counts. */ export type ElectronBoundarySummary = z.infer< typeof electronBoundarySummarySchema >;