import type { ValidationRule, ValidationContext } from '../interfaces'; import { ValidationSeverity } from '../interfaces'; /** * Configuration options for UnknownGlobalRule */ export interface UnknownGlobalOptions { /** * List of allowed global identifiers * Default: ['callTool', 'Math', 'JSON', 'Array', 'Object', 'String', 'Number', 'Date'] */ allowedGlobals?: string[]; /** * Whether to allow standard JavaScript globals (Infinity, NaN, isNaN, isFinite, etc.) * Default: true */ allowStandardGlobals?: boolean; /** * Custom error message */ message?: string; } /** * UnknownGlobalRule - Validates that all identifier references are either declared or allowed * * This rule implements a **whitelist-based approach** for identifiers: * - All identifiers must be either: * 1. Declared locally (variables, parameters, functions) * 2. Explicitly in the `allowedGlobals` list * 3. Standard safe globals (if enabled) * * **Purpose:** * - Prevent access to dangerous globals (process, require, window, etc.) * - Ensure explicit control over available APIs * - Create a secure sandbox with known capabilities * * **Example violations:** * ```javascript * console.log('hello'); // ❌ BLOCKED: console not in allowedGlobals * const x = process.env.HOME; // ❌ BLOCKED: process not allowed * fetch('https://api.com'); // ❌ BLOCKED: fetch not allowed * ``` * * **Valid code (with default allowedGlobals):** * ```javascript * const data = await callTool('users:list', {}); // ✅ callTool in allowedGlobals * const max = Math.max(1, 2, 3); // ✅ Math in allowedGlobals * const obj = JSON.parse('{"a":1}'); // ✅ JSON in allowedGlobals * const local = 42; // ✅ locally declared * ``` * * @example * ```typescript * const rule = new UnknownGlobalRule({ * allowedGlobals: ['callTool', 'getTool', 'Math', 'JSON'], * allowStandardGlobals: true, * }); * ``` */ export declare class UnknownGlobalRule implements ValidationRule { readonly name = "unknown-global"; readonly description = "Validates that all identifier references are either declared locally or in allowed globals list"; readonly defaultSeverity = ValidationSeverity.ERROR; readonly enabledByDefault = true; private readonly allowedGlobals; private readonly customMessage?; constructor(options?: UnknownGlobalOptions); validate(context: ValidationContext): void; /** * Collect all declared identifiers in the AST * * **Note on scope handling:** This method builds a flat symbol table without * tracking lexical scope. All declarations are collected into a single set * regardless of where they're declared. This is an intentional simplification * for performance reasons, and works correctly when used with AgentScript v1 * where user-defined functions are blocked by default (NoUserDefinedFunctionsRule). * * If user functions are enabled, inner-scope declarations will "whitelist" * that identifier name globally, which may cause false negatives. Example: * ```javascript * function inner() { const x = 1; } // declares 'x' * Math.max(x, 5); // 'x' passes because it's in the flat declared set * ``` */ private collectDeclarations; /** * Collect identifiers from patterns (destructuring, etc.) */ private collectPatternIdentifiers; /** * Check if this identifier node is part of a declaration */ private isDeclaration; /** * Check if this identifier is a property name (not a value reference) */ private isPropertyName; }