/** * Where a path actually leads — decided here, before the working command runs. * * Profile rules compare a path against directories, so only the canonical * form can be compared. Three sources of knowledge, each at its own level: * * local — tilde, working directory, `.`, `..`, doubled slashes; * passport — home directory, one cached probe per session; * server — where symbolic links actually lead, one probe per path. * * The server is asked only where rules are configured: without rules there * is nothing to determine. * * Only the path with the tilde expanded goes into the command, nothing * else. A collapsed `..` must not be sent: it is resolved after following a * link, not before it, and `/var/log/link/../x` means different files here * and on the server. The canonical form serves the judgment; the operation * runs on the caller's own path. */ import type { SSHExecutor } from './ssh-executor.js'; import type { SSHConfig } from '../utils/ssh-config.js'; export interface ExpandedPath { path: string; /** What a human needs to know: the path did not turn out to be the one they had in mind */ warnings: string[]; } /** * How path resolution ended: * * ok — the rules matched on everything that could be determined; * rewritten — the path had to be rewritten into another form (tilde expanded); * unverified — matched by name, but where links lead could not be determined; * denied — a profile rule blocks it. */ type PathOutcome = 'ok' | 'rewritten' | 'unverified' | 'denied'; export interface PathDecision { outcome: PathOutcome; /** The path to use for the command */ path: string; /** The canonical form the judgment was based on */ canonical: string; /** Where the server says the path leads, if it could be asked */ target?: string; warnings: string[]; /** Filled in only for denied */ reason?: string; } /** * A path the profile's rules refuse. * * The refusal is not a limit of the tool but a decision of the profile, so no * answer offers a way past it: pointing at the shell here would teach the * caller to walk around the rule that was set on purpose. */ export declare class PathDeniedError extends Error { readonly noExecHint: true; constructor(message: string); } /** * Resolve a path and decide what to do with it. * * The rule is applied twice: to the name and to where the name leads. If * either one denies it, the path is denied — otherwise a link inside an * allowed directory could carry data anywhere while still looking legitimate by name. */ export declare function decideRemotePath(executor: SSHExecutor, config: SSHConfig, path: string, options: { sudo?: boolean; }): Promise; /** * Expand a path and check it against the profile's access rules. * * The order is the whole point: the rules are applied to the path the * operation actually takes, not to the one the caller named. */ export declare function resolveRemotePath(executor: SSHExecutor, config: SSHConfig, path: string, options: { sudo?: boolean; }): Promise; export {};