/** * Indexing Policy Engine * * Determines which files should be indexed based on: * - Hardcoded deny list (security patterns - cannot be overridden) * - User exclude patterns from config * - Gitignore rules (including nested .gitignore files) * - Binary file detection (extension + content-based) * - File size limits * - User include patterns from config * * Priority order (first match wins): * 1. Hard Deny List -> If matches -> SKIP (always) * 2. User Exclude -> If matches config.exclude -> SKIP * 3. Gitignore -> If config.respectGitignore && matches -> SKIP * 4. Binary Detection -> If is binary file -> SKIP * 5. Size Check -> If > config.maxFileSize -> SKIP * 6. User Include -> If matches config.include -> INDEX * 7. Default -> INDEX * * Security features: * - Case-insensitive matching on Windows for deny list * - Content-based binary detection for unknown extensions * - Unicode path normalization to prevent bypass attacks */ import { Config } from '../storage/config.js'; /** * Whether the filesystem is case-insensitive (Windows) */ export declare const IS_CASE_INSENSITIVE_FS: boolean; /** * Normalize Unicode characters in a path for security * * This function prevents Unicode-based bypass attacks by: * - Normalizing to NFC form for consistent comparison * - Removing zero-width characters that could be used to hide content * - Removing RTL override characters that could disguise filenames * * @param p - The path to normalize * @returns Normalized path with dangerous Unicode sequences removed * * @example * ```typescript * // Remove zero-width characters * normalizePathUnicode('file\u200B.env') // => 'file.env' * * // Remove RTL overrides (could disguise "txt.exe" as "exe.txt") * normalizePathUnicode('\u202Efile.txt') // => 'file.txt' * ``` */ export declare function normalizePathUnicode(p: string): string; /** * Ignore interface from the 'ignore' package */ export interface Ignore { add(patterns: string | readonly string[]): Ignore; filter(pathnames: readonly string[]): string[]; createFilter(): (pathname: string) => boolean; ignores(pathname: string): boolean; test(pathname: string): { ignored: boolean; unignored: boolean; }; } /** * Hardcoded deny patterns organized by category * * These patterns are ALWAYS excluded for security and performance reasons. * They cannot be overridden by user configuration. */ export declare const HARDCODED_DENY_PATTERNS: { /** Package manager dependencies */ readonly dependencies: readonly ["node_modules/**", "jspm_packages/**", "bower_components/**", "vendor/**", ".venv/**", "venv/**", ".yarn/**", ".pnpm-store/**", "Pods/**", ".bundle/**", "deps/**"]; /** Version control system directories */ readonly versionControl: readonly [".git/**", ".hg/**", ".svn/**"]; /** Build output directories and framework caches */ readonly buildArtifacts: readonly ["dist/**", "build/**", "out/**", "target/**", "bin/**", "obj/**", "__pycache__/**", "_build/**", ".build/**", ".output/**", ".next/**", ".nuxt/**", ".angular/**", ".svelte-kit/**", ".astro/**", ".turbo/**", ".parcel-cache/**", ".cache/**", ".gradle/**", ".mvn/**", ".expo/**", ".docusaurus/**", ".storybook-static/**"]; /** Sensitive files that should never be indexed */ readonly secrets: readonly [".env", ".env.*", "*.pem", "*.key", "*.p12", "*.pfx"]; /** Log files and lock files */ readonly logsAndLocks: readonly ["*.log", "*.lock", "package-lock.json", "yarn.lock", "pnpm-lock.yaml", "Gemfile.lock", "poetry.lock"]; /** IDE and editor configuration */ readonly ideConfig: readonly [".idea/**", ".vscode/**", ".fleet/**", ".DS_Store", "*.swp", "*.swo", "*.sublime-workspace"]; /** Test coverage and cache directories */ readonly testing: readonly ["coverage/**", ".nyc_output/**", ".pytest_cache/**", ".hypothesis/**", ".tox/**", "htmlcov/**"]; /** Linter and type checker caches */ readonly linterCaches: readonly [".mypy_cache/**", ".ruff_cache/**", ".eslintcache", ".stylelintcache"]; /** Cloud and deployment caches */ readonly cloudDeploy: readonly [".terraform/**", ".serverless/**", ".vercel/**", ".netlify/**"]; }; /** * Flattened list of all hardcoded deny patterns */ export declare const ALL_DENY_PATTERNS: readonly string[]; /** * Result of a policy check */ export interface PolicyResult { /** Whether the file should be indexed */ shouldIndex: boolean; /** Reason for exclusion (only set when shouldIndex is false) */ reason?: string; /** Category of exclusion for debugging */ category?: 'hardcoded' | 'user-exclude' | 'gitignore' | 'binary' | 'size' | 'include-mismatch'; } /** * Load gitignore rules from a project directory * * Loads the root .gitignore and any nested .gitignore files. * Rules are applied relative to their containing directory. * * @param projectPath - Absolute path to the project root * @returns Ignore instance with all gitignore rules loaded */ export declare function loadGitignore(projectPath: string): Promise; /** * Check if a file is a binary file based on its path/extension * * Uses the 'is-binary-path' package for extension-based detection, * which is faster than reading file content. * * @param filePath - Path to check (can be relative or absolute) * @returns true if the file is likely a binary file based on extension */ export declare function isBinaryFile(filePath: string): boolean; /** * Check if a file contains binary content by reading its first bytes * * SECURITY: This provides defense-in-depth against renamed binary files. * For example, a malicious .exe renamed to .txt would be detected. * * @param absolutePath - Absolute path to the file * @param maxBytesToCheck - Maximum bytes to read (default: 8192) * @returns true if the file contains binary content (null bytes) */ export declare function isBinaryContent(absolutePath: string, maxBytesToCheck?: number): Promise; /** * Comprehensive binary file check using both extension and content detection * * SECURITY: Uses a two-phase approach: * 1. Fast extension-based check for known binary/text extensions * 2. Content-based check for unknown extensions to detect renamed binaries * * @param filePath - Relative path for extension check * @param absolutePath - Absolute path for content check * @returns true if the file is binary (either by extension or content) */ export declare function isBinaryFileOrContent(filePath: string, absolutePath: string): Promise; /** * Check if a file is under the size limit * * @param absolutePath - Absolute path to the file * @param maxSizeBytes - Maximum file size in bytes * @returns true if file is under the limit, false otherwise */ export declare function checkFileSize(absolutePath: string, maxSizeBytes: number): Promise<{ underLimit: boolean; actualSize: number; }>; /** * Check if a path matches any pattern in a list * * SECURITY: Applies Unicode normalization before matching to prevent bypass attacks. * * @param relativePath - Forward-slash separated relative path * @param patterns - Array of glob patterns * @param caseInsensitive - Whether to match case-insensitively (default: false) * @returns true if path matches any pattern */ export declare function matchesAnyPattern(relativePath: string, patterns: readonly string[], caseInsensitive?: boolean): boolean; /** * Check if a path is in the hardcoded deny list * * SECURITY: Uses case-insensitive matching on Windows to prevent bypasses like .ENV or .Env * * @param relativePath - Forward-slash separated relative path * @returns true if path matches hardcoded deny patterns */ export declare function isHardDenied(relativePath: string): boolean; /** * Determine if a file should be indexed * * Applies the policy rules in priority order: * 1. Hard Deny List -> SKIP (always) * 2. User Exclude -> SKIP * 3. Gitignore -> SKIP (if respectGitignore) * 4. Binary Detection -> SKIP (extension + content-based) * 5. Size Check -> SKIP (if over limit) * 6. User Include -> INDEX (if matches) * 7. Default -> INDEX * * SECURITY: All path checks apply Unicode normalization to prevent bypass attacks. * * @param relativePath - Forward-slash separated relative path from project root * @param absolutePath - Absolute path to the file * @param config - Project configuration * @param gitignore - Ignore instance with gitignore rules (or null to skip) * @returns PolicyResult indicating whether to index and why */ export declare function shouldIndex(relativePath: string, absolutePath: string, config: Config, gitignore: Ignore | null): Promise; /** * Indexing Policy Manager * * Provides a convenient interface for checking indexing policy. * Handles gitignore loading and caching. * * @example * ```typescript * const policy = new IndexingPolicy('/path/to/project', config); * await policy.initialize(); * * const result = await policy.shouldIndex('src/utils/hash.ts', '/path/to/project/src/utils/hash.ts'); * if (!result.shouldIndex) { * console.log('Skipping:', result.reason); * } * ``` */ export declare class IndexingPolicy { private readonly projectPath; private readonly config; private gitignore; private initialized; /** * Create a new IndexingPolicy instance * * @param projectPath - Absolute path to the project root * @param config - Project configuration */ constructor(projectPath: string, config: Config); /** * Initialize the policy engine * * Loads gitignore rules if respectGitignore is enabled. * Must be called before using shouldIndex. */ initialize(): Promise; /** * Check if a file should be indexed * * @param relativePath - Forward-slash separated relative path * @param absolutePath - Absolute path to the file * @returns PolicyResult */ shouldIndex(relativePath: string, absolutePath: string): Promise; /** * Check if a path is in the hardcoded deny list * * This is a synchronous check that doesn't require initialization. * * @param relativePath - Forward-slash separated relative path * @returns true if path matches hardcoded deny patterns */ isHardDenied(relativePath: string): boolean; /** * Get the project path */ getProjectPath(): string; /** * Get the configuration */ getConfig(): Config; /** * Check if the policy has been initialized */ isInitialized(): boolean; /** * Reload gitignore rules * * Useful when gitignore files have changed. */ reloadGitignore(): Promise; } //# sourceMappingURL=indexPolicy.d.ts.map