UNPKG

@mondaydotcomorg/atp-protocol

Version:

Core protocol types and interfaces for Agent Tool Protocol

129 lines 4.14 kB
/** * Input validation utilities for ExecutionConfig and other types */ import { z } from 'zod'; /** * Maximum allowed code size (1MB) */ export const MAX_CODE_SIZE = 1000000; export class ConfigValidationError extends Error { field; value; constructor(message, field, value) { super(message); this.field = field; this.value = value; this.name = 'ConfigValidationError'; } } export class SecurityViolationError extends Error { violations; constructor(message, violations) { super(message); this.violations = violations; this.name = 'SecurityViolationError'; } } /** * Sanitizes input string by removing control characters and normalizing whitespace */ export function sanitizeInput(input, maxLength = MAX_CODE_SIZE) { if (typeof input !== 'string') { return ''; } let sanitized = input.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, ''); sanitized = sanitized.replace(/[\u200B-\u200D\uFEFF]/g, ''); sanitized = sanitized.replace(/\n{10,}/g, '\n\n\n'); if (sanitized.length > maxLength) { sanitized = sanitized.substring(0, maxLength); } return sanitized; } /** * Frames user code in a secure execution context to prevent injection attacks * Similar to SQL parameterized queries - treats user code as data within a safe boundary */ export function frameCodeExecution(userCode) { const cleaned = sanitizeInput(userCode); return ` (async function __user_code_context__() { "use strict"; ${cleaned} })(); `.trim(); } /** * Zod schema for ExecutionConfig validation */ export const executionConfigSchema = z.object({ timeout: z .number({ invalid_type_error: 'timeout must be a number', }) .positive('timeout must be positive') .max(300000, 'timeout cannot exceed 300000ms (5 minutes)') .optional(), maxMemory: z .number({ invalid_type_error: 'maxMemory must be a number', }) .positive('maxMemory must be positive') .max(512 * 1024 * 1024, 'maxMemory cannot exceed 512MB') .optional(), maxLLMCalls: z .number({ invalid_type_error: 'maxLLMCalls must be a number', }) .nonnegative('maxLLMCalls cannot be negative') .max(1000, 'maxLLMCalls cannot exceed 1000') .optional(), allowedAPIs: z .array(z.string().refine((val) => val.trim().length > 0, { message: 'allowedAPIs must contain non-empty strings', })) .optional(), allowLLMCalls: z .boolean({ invalid_type_error: 'allowLLMCalls must be a boolean', }) .optional(), progressCallback: z.function().optional(), customLLMHandler: z.function().optional(), clientServices: z.any().optional(), provenanceMode: z.any().optional(), securityPolicies: z.array(z.any()).optional(), provenanceHints: z.array(z.string()).optional(), }); /** * Validates ExecutionConfig parameters using Zod */ export function validateExecutionConfig(config) { try { executionConfigSchema.parse(config); } catch (error) { if (error instanceof z.ZodError) { const errors = error.errors.map((err) => err.message); throw new ConfigValidationError(`Invalid ExecutionConfig: ${errors.join(', ')}`, 'ExecutionConfig', config); } throw error; } } /** * Validates client ID format */ export function validateClientId(clientId) { if (typeof clientId !== 'string') { throw new ConfigValidationError('clientId must be a string', 'clientId', clientId); } if (clientId.trim().length === 0) { throw new ConfigValidationError('clientId cannot be empty', 'clientId', clientId); } if (clientId.length > 256) { throw new ConfigValidationError('clientId cannot exceed 256 characters', 'clientId', clientId); } if (!/^[a-zA-Z0-9_-]+$/.test(clientId)) { throw new ConfigValidationError('clientId can only contain alphanumeric characters, dashes, and underscores', 'clientId', clientId); } } //# sourceMappingURL=validation.js.map