/** * Path confinement for values that came from an analyzed repository. * * OpenLore reads repositories it does not trust (SECURITY.md scopes exactly that), * and two of the values it acts on are attacker-authored: `openspecPath` in the * committed `.openlore/config.json`, and the layout of `openspec/` itself — a repo * can commit a SYMLINK there, and git will check it out. Neither may be allowed to * redirect a read or a write outside the project root. * * These primitives live in a leaf module (no OpenLore imports) because the sites * that need them span the MCP handlers, the CLI, the decision syncer and the * analyzer; a shared guard that only one face can import is how the drift that * motivated this file happened in the first place. */ /** * Resolve a user-supplied relative file path against a validated project root and * ensure the result stays within that root — by BOTH a lexical check (cheap, blocks * `../` traversal) AND a canonical, symlink-resolved check (mcp-security: * Symlink-Aware Path Confinement). The canonical check defeats an in-root symlink * that points outside the root: confinement is enforced on the real path of the * target where it exists, and on the real path of its nearest existing ancestor * where it does not (so a not-yet-created write target is confined too). */ export declare function safeJoin(absDir: string, filePath: string): string; /** * True when `absPath` stays inside `absRoot` both lexically and canonically. * * The predicate form of {@link safeJoin}, for the walkers that enumerate paths * themselves (a `readdir` of `openspec/specs`) rather than joining a caller's * string: they need to DROP an escaping entry and carry on, not abort the walk. */ export declare function isConfinedPath(absRoot: string, absPath: string): boolean; /** * Resolve the project's openspec directory, confined to the validated root. * * `config.openspecPath` is read from `.openlore/config.json` — an untrusted on-disk * artifact (mcp-security threat model). A poisoned value (`../../etc`, an absolute * escape) must not redirect the reads/writes that derive from it (spec/manifest * reads, decision ADR reads, decision sync writes) outside the project root. We * confine via safeJoin; a value that escapes the root falls back to the default * `openspec/` dir — a legitimate in-root path (default or custom) passes through * unchanged, so only an escaping value is neutralized. */ export declare function safeOpenspecDir(absRoot: string, configuredPath: string | undefined, onFallback?: (message: string) => void): string; //# sourceMappingURL=path-confinement.d.ts.map