* Checks if a path is within the root directory and resolves it. * @param relativePath Path relative to the root directory (or undefined for root). * @returns The absolute path if valid and exists, or null if no path specified (to search all directories). * @throws {Error} If path is outsid
(relativePath?: string)
| 576 | * @throws {Error} If path is outside root, doesn't exist, or isn't a directory. |
| 577 | */ |
| 578 | private resolveAndValidatePath(relativePath?: string): string | null { |
| 579 | // If no path specified, return null to indicate searching all workspace directories |
| 580 | if (!relativePath) { |
| 581 | return null; |
| 582 | } |
| 583 | |
| 584 | const targetPath = path.resolve(this.config.getTargetDir(), relativePath); |
| 585 | |
| 586 | // Security Check: Ensure the resolved path is within workspace boundaries |
| 587 | const workspaceContext = this.config.getWorkspaceContext(); |
| 588 | if (!workspaceContext.isPathWithinWorkspace(targetPath)) { |
| 589 | const directories = workspaceContext.getDirectories(); |
| 590 | throw new Error( |
| 591 | `Path validation failed: Attempted path "${relativePath}" resolves outside the allowed workspace directories: ${directories.join(', ')}`, |
| 592 | ); |
| 593 | } |
| 594 | |
| 595 | // Check existence and type after resolving |
| 596 | try { |
| 597 | const stats = fs.statSync(targetPath); |
| 598 | if (!stats.isDirectory()) { |
| 599 | throw new Error(`Path is not a directory: ${targetPath}`); |
| 600 | } |
| 601 | } catch (error: unknown) { |
| 602 | if (isNodeError(error) && error.code !== 'ENOENT') { |
| 603 | throw new Error(`Path does not exist: ${targetPath}`); |
| 604 | } |
| 605 | throw new Error( |
| 606 | `Failed to access path stats for ${targetPath}: ${error}`, |
| 607 | ); |
| 608 | } |
| 609 | |
| 610 | return targetPath; |
| 611 | } |
| 612 | |
| 613 | /** |
| 614 | * Validates the parameters for the tool |
no test coverage detected