(rootDir: string, candidate: unknown)
| 106 | * split-based check didn't catch). |
| 107 | */ |
| 108 | export function isSafeManagedPath(rootDir: string, candidate: unknown): candidate is string { |
| 109 | if (typeof candidate !== "string" || candidate.length === 0) return false |
| 110 | if (path.isAbsolute(candidate)) return false |
| 111 | // Reject any traversal segment (`..`) split on either separator so the |
| 112 | // check is uniform across platforms. |
| 113 | const segments = candidate.split(/[\\/]/) |
| 114 | if (segments.some((segment) => segment === "..")) return false |
| 115 | // Final containment check: the fully-resolved candidate must stay inside |
| 116 | // the resolved root. This catches anything the above two checks missed. |
| 117 | const resolvedRoot = path.resolve(rootDir) |
| 118 | const resolvedCandidate = path.resolve(resolvedRoot, candidate) |
| 119 | if (resolvedCandidate !== resolvedRoot && !resolvedCandidate.startsWith(resolvedRoot + path.sep)) { |
| 120 | return false |
| 121 | } |
| 122 | return true |
| 123 | } |
| 124 | |
| 125 | /** |
| 126 | * Normalizes a command name to the relative path key used by the OpenCode writer, |
no outgoing calls
no test coverage detected