/** * Path Boundary — project-root security boundary enforcement. * * The MCP server establishes ONE explicit allowed project root at startup. * All filesystem operations (scan target, config load, suppression read/write, * baseline read, custom rulepack load, output paths) must be constrained to * that root. * * Containment strategy: * - absolute resolution * - realpath where target exists (symlink-aware containment) * - normalized separators * - Windows case-insensitive path comparison * - UNC/outside-root path rejection * * This module NEVER silently normalizes an outside-root path back inside. * On any escape it throws PathBoundaryError with code TARGET_OUTSIDE_ALLOWED_ROOT * (or SYMLINK_ESCAPE / INVALID_PATH). * * Architectural pattern adapted (READ-ONLY reference) from the ai-appsec * producer's src/security/path-boundary.ts. No detector/rule semantics reused. * No runtime dependency on ai-appsec. * * PRODUCER_LOCAL_V2_CONFORMANCE. */ export type PathBoundaryErrorCode = 'TARGET_OUTSIDE_ALLOWED_ROOT' | 'SYMLINK_ESCAPE' | 'INVALID_PATH'; export declare class PathBoundaryError extends Error { readonly code: PathBoundaryErrorCode; readonly target?: string; readonly real?: string; constructor(code: PathBoundaryErrorCode, message: string, details?: { target?: string; real?: string; }); } export interface ResolveOptions { /** * Whether to resolve symlinks via realpath when the target exists. * Default: true. Set false only for paths that may not exist yet * (e.g. an output file about to be written) — lexical containment * is still enforced. */ readonly resolveSymlinks?: boolean; /** * If true and the target does not exist, allow the resolved lexical path * (still must be within root). Default: true (so output paths for files * not yet created are allowed). Set false to require existence. */ readonly allowMissing?: boolean; } export declare class PathBoundary { private readonly root; private readonly rootNormalized; private constructor(); /** * Create a PathBoundary rooted at the given directory. * The root is resolved to an absolute, real path and verified to be a directory. */ static create(root: string): Promise; /** * Create a PathBoundary without async realpath (used for already-canonical roots). * Prefer create() wherever possible. */ static createSync(root: string): PathBoundary; /** * Resolve a target path relative to the root, enforcing boundary constraints. * Throws PathBoundaryError if the path escapes the root. * * - Absolute targets are checked against root (must be within root). * - Relative targets are joined to root. * - `..` traversal that escapes root is rejected. * - Symlinks that resolve outside root are rejected. * - UNC paths are rejected. */ resolve(target: string, options?: ResolveOptions): Promise; /** * Synchronous lexical containment check (no symlink resolution). * Use only when async realpath is not available; prefer resolve() for full safety. */ contains(target: string): boolean; /** The canonical root path (realpath-resolved if created via create()). */ getRoot(): string; } //# sourceMappingURL=path-boundary.d.ts.map