@akms/mcp-ssh 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cli.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/_defs/defaults.ts","../src/_defs/command-rules.ts","../src/_defs/protected-paths.ts","../src/_defs/env-vars.ts","../src/_libs/logger.ts","../src/_libs/text.ts","../src/_libs/fs-path.ts","../src/modules/guard/command-guard.ts","../src/modules/guard/path-guard.ts","../src/modules/guard/guard-error.ts","../src/modules/ssh/ssh-connection.ts","../src/modules/ssh/session-manager.ts","../src/modules/ssh/sftp-operations.ts","../src/modules/config/config-schema.ts","../src/modules/config/env-host.ts","../src/modules/config/load-config.ts","../src/modules/tools/format.ts","../src/modules/tools/tool-context.ts","../src/modules/tools/exec-tools.ts","../src/modules/tools/file-tools.ts","../src/modules/tools/host-tools.ts","../src/modules/tools/session-tools.ts","../src/modules/tools/index.ts","../src/server.ts","../src/cli.ts"],"names":["path","fs","StringDecoder","os","z"],"mappings":"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","file":"cli.js","sourcesContent":["/** Env var holding an explicit config file path. */\nexport const CONFIG_PATH_ENV = \"SSH_MCP_CONFIG\";\n\n/** Env var overriding the stderr log level (\"debug\" | \"info\" | \"warn\" | \"error\" | \"silent\"). */\nexport const LOG_LEVEL_ENV = \"SSH_MCP_LOG_LEVEL\";\n\n/** Looked up under the home directory when CONFIG_PATH_ENV is unset. */\nexport const DEFAULT_CONFIG_FILENAMES = [\n \".akms-ssh.json\",\n \".config/akms-ssh/config.json\",\n];\n\nexport const DEFAULT_SSH_PORT = 22;\n\nexport const DEFAULT_EXEC_TIMEOUT_MS = 60_000;\n\nexport const DEFAULT_CONNECT_TIMEOUT_MS = 20_000;\n\n/** stdout / stderr cutoff — roughly 25k tokens of context at worst. */\nexport const DEFAULT_MAX_OUTPUT_CHARACTERS = 100_000;\n\nexport const DEFAULT_MAX_READ_FILE_BYTES = 200_000;\n\n/** ssh2 keepalive so idle sessions survive NAT / firewall timeouts. */\nexport const KEEPALIVE_INTERVAL_MS = 15_000;\n\n/** Sessions untouched for this long are closed by the sweeper. */\nexport const SESSION_IDLE_TIMEOUT_MS = 15 * 60 * 1000;\n\nexport const SESSION_SWEEP_INTERVAL_MS = 60_000;\n\n/** Emitted after the user command so the session can track `cd` between execs. */\nexport const CWD_MARKER = \"__AKMS_SSH_CWD__\";\n\n/** `ssh_list_dir` stops here — a directory with 500k entries would otherwise return megabytes. */\nexport const MAX_DIRECTORY_ENTRIES = 1_000;\n\nexport const SERVER_NAME = \"akms-ssh\";\n\nexport const SERVER_VERSION = \"0.0.1\";\n","/** One deny rule: a regex tested against a command segment plus the message shown on a hit. */\nexport interface CommandRule {\n pattern: RegExp;\n reason: string;\n}\n\n/**\n * A rule keyed on the resolved binary plus the shape of its operands.\n *\n * Regex-only rules could not express \"`rm -rf` where *any* operand is a critical path\" —\n * an anchored pattern reads operands positionally, so `rm -rf /tmp/x /` slipped through\n * because the root argument was not the first one.\n */\nexport interface ArgumentRule {\n binaries: string[];\n /** Rule fires only when at least one flag matches this, when set. */\n requiredFlagPattern?: RegExp;\n /** Tested against every non-flag operand. */\n argumentPattern: RegExp;\n reason: string;\n}\n\n/**\n * Directories whose recursive deletion or permission rewrite destroys the machine.\n * Anchored as a whole-operand match, so `/var/log/myapp` stays allowed while\n * `/var`, `/var/`, `/var/*` do not.\n */\nexport const CRITICAL_PATH_PATTERN = new RegExp(\n \"^(?:\"\n + \"/|//|/\\\\*|/\\\\.|/\\\\.\\\\.|/\\\\*/|//\\\\*|\"\n + \"~|~/|~/\\\\*|\\\\$HOME|\\\\$HOME/|\\\\$HOME/\\\\*|\\\\$\\\\{HOME\\\\}/?\\\\*?|\"\n + \"/(?:bin|boot|dev|etc|home|lib|lib32|lib64|libx32|media|mnt|opt|proc|root|run|sbin|srv|sys|usr|var|data)(?:/\\\\*)?/?\"\n + \")$\",\n \"i\"\n);\n\n/** Individual files whose loss alone bricks the host or locks everyone out. */\nexport const CRITICAL_FILE_PATTERN = new RegExp(\n \"^/(?:\"\n + \"etc/(?:passwd|shadow|group|sudoers|fstab|hostname|hosts|resolv\\\\.conf)\"\n + \"|boot/(?:vmlinuz|initrd|grub).*\"\n + \"|etc/ssh/sshd_config\"\n + \")$\",\n \"i\"\n);\n\n/**\n * Binaries that only wrap another command — the guard steps past them (and their flags,\n * `FOO=bar` assignments, and numeric operands like `timeout 30`) to the binary that runs.\n */\nexport const COMMAND_WRAPPER_BINARIES = [\n \"sudo\",\n \"doas\",\n \"env\",\n \"eval\",\n \"nohup\",\n \"time\",\n \"nice\",\n \"ionice\",\n \"timeout\",\n \"stdbuf\",\n \"command\",\n \"exec\",\n \"builtin\",\n \"watch\",\n \"xargs\",\n \"setsid\",\n \"unbuffer\",\n \"busybox\",\n \"toybox\",\n];\n\n/**\n * `timeout 30 cmd`, `nice -n 10 cmd`, `watch 2 cmd` — these wrappers take a bare numeric\n * operand before the real command, so a duration must not be mistaken for the binary.\n */\nexport const NUMERIC_OPERAND_PATTERN = /^\\d+(?:\\.\\d+)?[smhd]?$/i;\n\n/**\n * Wrapper flags that consume the following token as their value.\n *\n * Without this, `env -u FOO rm -rf /` resolves its binary to `FOO`: the flag is skipped,\n * its value is not, and every binary-keyed rule then looks at the wrong word.\n */\nexport const WRAPPER_VALUE_FLAGS: Record<string, string[]> = {\n env: [\"-u\", \"--unset\", \"-C\", \"--chdir\", \"-S\", \"--split-string\"],\n sudo: [\"-u\", \"--user\", \"-g\", \"--group\", \"-p\", \"--prompt\", \"-C\", \"--close-from\", \"-h\", \"--host\", \"-D\", \"--chdir\", \"-R\", \"--chroot\"],\n doas: [\"-u\", \"-C\"],\n timeout: [\"-s\", \"--signal\", \"-k\", \"--kill-after\"],\n nice: [\"-n\", \"--adjustment\"],\n ionice: [\"-c\", \"--class\", \"-n\", \"--classdata\", \"-p\", \"--pid\"],\n stdbuf: [\"-i\", \"--input\", \"-o\", \"--output\", \"-e\", \"--error\"],\n xargs: [\"-a\", \"--arg-file\", \"-d\", \"--delimiter\", \"-E\", \"-I\", \"--replace\", \"-L\", \"-n\", \"--max-args\", \"-P\", \"--max-procs\", \"-s\", \"--max-chars\"],\n watch: [\"-n\", \"--interval\"],\n setsid: [],\n nohup: [],\n \"systemd-run\": [\"-u\", \"--unit\", \"-p\", \"--property\", \"--uid\", \"--gid\", \"--setenv\"],\n runuser: [\"-u\", \"--user\", \"-g\", \"--group\", \"-s\", \"--shell\"],\n su: [\"-s\", \"--shell\", \"-g\", \"--group\"],\n};\n\n/** Rejected when `allowSudo` is false. Default profiles allow these. */\nexport const PRIVILEGE_ESCALATION_BINARIES = [\n \"sudo\",\n \"su\",\n \"doas\",\n \"pkexec\",\n \"runuser\",\n \"chroot\",\n \"nsenter\",\n \"systemd-run\",\n];\n\n/**\n * Binaries that take a command *string* (`-c \"…\"`) and run it in a fresh shell.\n * The payload is pulled out and screened as its own command — otherwise\n * `bash -c \"rm -rf /\"` would only ever be judged as \"the binary is bash\".\n */\nexport const SHELL_PAYLOAD_BINARIES = [\n \"sh\",\n \"bash\",\n \"zsh\",\n \"ksh\",\n \"dash\",\n \"ash\",\n \"mksh\",\n \"csh\",\n \"tcsh\",\n \"fish\",\n \"su\",\n \"runuser\",\n \"chroot\",\n \"nsenter\",\n \"systemd-run\",\n];\n\n/**\n * Always rejected, on every profile, not configurable.\n *\n * Scope is deliberately narrow: **irreversible destruction of the machine, or cutting the\n * connection you are working through**. Everything short of that — installing packages,\n * restarting services, deleting an application's files, piping an install script into a\n * shell — is ordinary administration and is allowed by default. A profile that wants more\n * restraint opts in with `readonly`, `allowCommands` or `denyPatterns`.\n */\nexport const DANGEROUS_COMMAND_RULES: CommandRule[] = [\n {\n pattern: /^mkfs(\\.\\w+)?\\b/i,\n reason: \"formats a filesystem\",\n },\n {\n pattern: />\\s*\\/dev\\/(sd|nvme|hd|vd|xvd|mapper)/i,\n reason: \"redirects output onto a block device\",\n },\n {\n pattern: /^(shutdown|reboot|halt|poweroff)\\b/i,\n reason: \"powers off or reboots the host, ending this session\",\n },\n {\n pattern: /^init\\s+[06]\\b/i,\n reason: \"changes runlevel to halt or reboot\",\n },\n {\n pattern: /^systemctl\\s+(poweroff|reboot|halt|emergency|rescue)\\b/i,\n reason: \"powers off, reboots or degrades the host\",\n },\n {\n // Anchored on `/` as the whole search root: `find /tmp -delete` is ordinary\n // cleanup, `find / -delete` empties the machine.\n pattern: /^find\\s+\\/\\s+.*(-delete|-exec(dir)?\\s+(\\/\\S+\\/)?rm)/i,\n reason: \"deletes files found from the filesystem root\",\n },\n {\n pattern: /^crontab\\s+(-\\S+\\s+)*-r\\b/i,\n reason: \"removes every cron job for the user\",\n },\n {\n pattern: /^(iptables|ip6tables|nft)\\s+(-F|--flush|flush)\\b/i,\n reason: \"flushes firewall rules and can lock this session out\",\n },\n {\n pattern: /--no-preserve-root/i,\n reason: \"explicitly disables the root-deletion safeguard\",\n },\n];\n\n/** Danger rules keyed on the binary plus its operands. */\nexport const DANGEROUS_ARGUMENT_RULES: ArgumentRule[] = [\n {\n binaries: [\"rm\"],\n requiredFlagPattern: /^--?(?:[a-z]*[rRf][a-z]*|recursive|force)$/,\n argumentPattern: CRITICAL_PATH_PATTERN,\n reason: \"deletes the filesystem root, a system directory or an entire home directory\",\n },\n {\n binaries: [\"rm\", \"unlink\", \"shred\", \"srm\", \"wipe\"],\n argumentPattern: CRITICAL_FILE_PATTERN,\n reason: \"deletes a file the host cannot boot or authenticate without\",\n },\n {\n binaries: [\"shred\", \"srm\", \"wipe\"],\n argumentPattern: CRITICAL_PATH_PATTERN,\n reason: \"irreversibly destroys a system path\",\n },\n {\n binaries: [\"chmod\", \"chown\", \"chgrp\"],\n requiredFlagPattern: /^--?(R|recursive)$/,\n argumentPattern: CRITICAL_PATH_PATTERN,\n reason: \"recursively rewrites ownership or permissions on a system path\",\n },\n {\n binaries: [\"dd\"],\n argumentPattern: /^of=(\\/dev\\/(?!null|zero|stdout|stderr|tty)|\\/etc\\/|\\/boot\\/|\\/bin\\/|\\/sbin\\/|\\/usr\\/|\\/lib)/i,\n reason: \"writes raw bytes over a device or system file\",\n },\n {\n binaries: [\"mkfs\", \"fdisk\", \"parted\", \"sgdisk\", \"wipefs\"],\n argumentPattern: /^\\/dev\\//i,\n reason: \"repartitions or formats a block device\",\n },\n];\n\n/** Danger rules tested against the whole command, before it is split on `;`, `&&`, `|`. */\nexport const DANGEROUS_PIPELINE_RULES: CommandRule[] = [\n {\n pattern: /\\{\\s*:\\s*\\|\\s*:\\s*&\\s*\\}/,\n reason: \"fork bomb\",\n },\n];\n\n/**\n * Blocked when the profile is read-only: binaries whose whole purpose is to change the\n * host's files, packages, services or accounts.\n *\n * Interpreters, `awk`, database clients and archive listing are deliberately **absent**.\n * A read-only profile exists to make a host safe to *inspect*, and log analysis routinely\n * needs `python3 -c`, `awk`, `psql`. Blocking them made the mode unusable for its own\n * purpose while stopping nobody who wanted around it — a shell payload is still screened\n * (see SHELL_PAYLOAD_BINARIES), so `bash -c \"rm x\"` is caught by the `rm` rule.\n */\nexport const WRITE_COMMAND_BINARIES = [\n // filesystem mutation\n \"rm\", \"rmdir\", \"mv\", \"cp\", \"dd\", \"mkdir\", \"touch\", \"ln\", \"chmod\", \"chown\", \"chgrp\",\n \"truncate\", \"shred\", \"srm\", \"wipe\", \"install\", \"tee\", \"patch\", \"rename\", \"chattr\", \"setfacl\",\n // storage / mounts\n \"mkfs\", \"fdisk\", \"parted\", \"sgdisk\", \"wipefs\", \"mount\", \"umount\", \"swapon\", \"swapoff\",\n // accounts and scheduling\n \"useradd\", \"usermod\", \"userdel\", \"groupadd\", \"groupmod\", \"groupdel\",\n \"passwd\", \"chpasswd\", \"visudo\", \"crontab\", \"at\", \"batch\",\n // process and power control\n \"kill\", \"killall\", \"pkill\", \"reboot\", \"shutdown\", \"halt\", \"poweroff\", \"init\", \"service\",\n // package managers\n \"apt\", \"apt-get\", \"aptitude\", \"dpkg\", \"yum\", \"dnf\", \"rpm\", \"zypper\", \"pacman\", \"apk\",\n \"snap\", \"brew\", \"npm\", \"pnpm\", \"yarn\", \"npx\", \"pip\", \"pip3\", \"gem\", \"cargo\", \"composer\",\n \"bundle\", \"make\", \"cmake\",\n // editors — interactive and write-oriented\n \"vi\", \"vim\", \"nvim\", \"nano\", \"emacs\", \"ex\", \"ed\",\n // transfer to/from other hosts, and archive extraction\n \"scp\", \"rsync\", \"sftp\", \"ftp\", \"ssh\", \"ssh-keygen\", \"ssh-copy-id\", \"wget\",\n \"unzip\", \"gunzip\", \"bunzip2\", \"unxz\", \"cpio\",\n // firewall\n \"iptables\", \"ip6tables\", \"ufw\", \"firewall-cmd\", \"nft\",\n];\n\n/**\n * Blocked when the profile is read-only: tools that read *or* write depending on the\n * subcommand or flag, so only the mutating form is matched.\n */\nexport const WRITE_USAGE_RULES: CommandRule[] = [\n {\n pattern: /^sed\\b.*(?:(\\s|^)-[a-zA-Z]*i([a-zA-Z]|\\s|$|\\.)|--in-place)/,\n reason: \"sed edits files in place\",\n },\n {\n pattern: /^sort\\b.*(\\s|^)(-o|--output)\\b/i,\n reason: \"sort writes its result to a file\",\n },\n {\n pattern: /^find\\b.*(-delete|-exec|-execdir|-ok|-okdir|-fls|-fprint)/i,\n reason: \"find action deletes files or runs an arbitrary command\",\n },\n {\n pattern: /^git\\s+(push|reset|checkout|switch|restore|clean|rebase|merge|commit|add|rm|mv|stash|apply|revert|cherry-pick|pull|remote|tag|gc|prune|init|clone)\\b/i,\n reason: \"git subcommand mutates the working tree or the remote\",\n },\n {\n pattern: /^systemctl\\s+(start|stop|restart|reload|enable|disable|mask|unmask|kill|isolate|set-property|edit|daemon-reload|daemon-reexec)\\b/i,\n reason: \"systemctl subcommand changes service state\",\n },\n {\n pattern: /^docker\\s+(run|rm|rmi|stop|start|restart|kill|exec|create|build|push|pull|cp|commit|prune|load|import|tag|update|rename|volume|network|swarm)\\b/i,\n reason: \"docker subcommand mutates containers, images or volumes\",\n },\n {\n pattern: /^(kubectl|oc)\\s+(apply|delete|create|edit|scale|patch|replace|rollout|drain|cordon|uncordon|exec|cp|set|annotate|label|taint)\\b/i,\n reason: \"kubectl subcommand mutates cluster state\",\n },\n {\n pattern: /^tar\\b.*(--extract|--create|--delete|(\\s|^)-{1,2}[a-zA-Z]*[xc][a-zA-Z]*(\\s|$))/i,\n reason: \"tar extract/create writes files\",\n },\n {\n pattern: /^curl\\b.*(\\s|^)(-o|-O|--output|--remote-name|--upload-file|-T)\\b/i,\n reason: \"curl writes a file or uploads one\",\n },\n {\n pattern: /^(zip|gzip|bzip2|xz)\\b/i,\n reason: \"compression tool rewrites files on disk\",\n },\n];\n\n/**\n * Harmless redirection forms stripped before checking for output redirection —\n * `2>&1`, `>/dev/null`, `&>/dev/null` are diagnostics plumbing, not writes.\n */\nexport const BENIGN_REDIRECT_PATTERN = /(\\d?>>?\\s*&\\s*\\d|&>>?\\s*\\/dev\\/null|\\d?>>?\\s*\\/dev\\/null)/g;\n\n/** Any remaining `>` after the benign forms are stripped means a real file write. */\nexport const OUTPUT_REDIRECT_PATTERN = />/;\n\n/** Leading `2>`, `>>`, `<`, `2>&1` tokens — stripped so the binary scan finds the command. */\nexport const REDIRECTION_TOKEN_PATTERN = /^(?:\\d*>>?|<|&>>?)/;\n\n/**\n * A redirection operator with no target attached, so the *next* token is its filename\n * rather than a command. `2>&1` is excluded: it names its target inline.\n */\nexport const BARE_REDIRECTION_OPERATOR_PATTERN = /^(?:\\d*>>?|<|&>>?)$/;\n\n/**\n * Shell word splitting: redirection operators first so `tee</dev/null` yields\n * `tee`, `<`, `/dev/null` instead of one word whose basename reads as \"null\".\n */\nexport const SHELL_TOKEN_PATTERN = /\\d*>>?&?\\d*|&>>?|<&?\\d*|(?:[^\\s'\"\\\\<>&|]|\\\\.|'[^']*'|\"[^\"]*\")+/g;\n\n/** Shell grouping and keyword tokens that precede a command rather than being one. */\nexport const SHELL_KEYWORD_TOKENS = [\n \"if\", \"then\", \"else\", \"elif\", \"fi\",\n \"for\", \"while\", \"until\", \"do\", \"done\",\n \"case\", \"esac\", \"in\", \"select\",\n \"function\", \"{\", \"}\", \"(\", \")\", \"!\", \"[[\", \"]]\", \"[\", \"]\",\n];\n\n/**\n * Shell metacharacters forbidden in a `cwd` argument.\n *\n * `cwd` is interpolated into the generated `cd` prefix, so anything that can end a word\n * and start a new command is remote code execution that never passes through the command\n * guard. Directory names legitimately containing these are vanishingly rare; the trade is\n * obviously worth it.\n */\nexport const UNSAFE_PATH_CHARACTER_PATTERN = /[`$;|&<>(){}!*?\\[\\]\\\\\"'\\n\\r\\t]/;\n","import type { CommandRule } from \"./command-rules\";\n\n/**\n * Local paths the file tools may never read or write, whatever the profile allows.\n *\n * Deliberately narrow — two categories only:\n *\n * 1. **Credentials.** Uploading these exfiltrates the operator's keys to a remote host.\n * 2. **Files that define the guards themselves** — this server's config and the MCP\n * client's, plus autostart locations. Downloading onto one of these replaces the\n * policy that governs the next run, so the guard would be self-defeating without it.\n *\n * Ordinary operational files are intentionally *not* here. `.env` uploads, `.bashrc`\n * backups and cron fetches are normal deployment work, and blocking them broke real tasks\n * to stop an attack that a `python3 -c` one-liner performs anyway.\n *\n * Matched against the **real** path (symlinks resolved) with `\\` normalized to `/`.\n */\nexport const PROTECTED_LOCAL_PATH_RULES: CommandRule[] = [\n {\n pattern: /(^|\\/)\\.ssh(\\/|$)/i,\n reason: \"SSH key directory\",\n },\n {\n pattern: /(^|\\/)authorized_keys$/i,\n reason: \"SSH authorized_keys\",\n },\n {\n pattern: /(^|\\/)id_(rsa|dsa|ecdsa|ed25519)/i,\n reason: \"private key file\",\n },\n {\n pattern: /\\.(pem|ppk|p12|pfx|key)$/i,\n reason: \"private key or certificate file\",\n },\n {\n pattern: /(^|\\/)\\.gnupg(\\/|$)/i,\n reason: \"GPG keyring\",\n },\n {\n pattern: /(^|\\/)\\.aws(\\/|$)/i,\n reason: \"AWS credentials\",\n },\n {\n pattern: /(^|\\/)\\.kube(\\/|$)/i,\n reason: \"kubeconfig\",\n },\n {\n pattern: /(^|\\/)\\.docker(\\/|$)/i,\n reason: \"docker credentials\",\n },\n {\n pattern: /(^|\\/)\\.npmrc$/i,\n reason: \"npm credentials\",\n },\n {\n pattern: /(^|\\/)\\.netrc$/i,\n reason: \"netrc credentials\",\n },\n {\n pattern: /(^|\\/)\\.?akms-ssh(\\.json)?(\\/|$)/i,\n reason: \"this server's own host profile configuration\",\n },\n {\n pattern: /(^|\\/)\\.claude(\\.json)?(\\/|$)/i,\n reason: \"MCP client configuration\",\n },\n {\n pattern: /(^|\\/)\\.mcp\\.json$/i,\n reason: \"MCP server configuration\",\n },\n {\n pattern: /(^|\\/)claude_desktop_config\\.json$/i,\n reason: \"MCP client configuration\",\n },\n {\n pattern: /(^|\\/)start ?menu\\/programs\\/startup(\\/|$)/i,\n reason: \"Windows startup folder\",\n },\n {\n pattern: /(^|\\/)\\.config\\/autostart(\\/|$)/i,\n reason: \"desktop autostart directory\",\n },\n];\n","/**\n * Environment variables that define a **single host**, one MCP server entry per host.\n *\n * This is the primary way to configure the server. Each variable is a plain value, so an\n * MCP client's `env` block reads like a connection form — no JSON inside JSON, no\n * escaped quotes, and a typo shows up on the line it is on.\n *\n * `SSH_MCP_CONFIG` remains for the case where one server really does front several hosts.\n */\nexport const SINGLE_HOST_ENV = {\n /** Presence of this variable selects single-host mode. */\n HOST: \"SSH_HOST\",\n PORT: \"SSH_PORT\",\n USER: \"SSH_USER\",\n /** Path to a private key file. */\n KEY: \"SSH_KEY\",\n PASSPHRASE: \"SSH_PASSPHRASE\",\n PASSWORD: \"SSH_PASSWORD\",\n /** Pinned host key, `SHA256:…`. */\n HOST_KEY: \"SSH_HOST_KEY\",\n /** Alias shown to the model; defaults to the hostname. */\n NAME: \"SSH_NAME\",\n DESCRIPTION: \"SSH_DESCRIPTION\",\n /** Directory new sessions start in. */\n CWD: \"SSH_CWD\",\n READONLY: \"SSH_READONLY\",\n ALLOW_SUDO: \"SSH_ALLOW_SUDO\",\n /** Comma-separated binary names. */\n ALLOW_COMMANDS: \"SSH_ALLOW_COMMANDS\",\n /** Comma-separated regex sources. */\n DENY_PATTERNS: \"SSH_DENY_PATTERNS\",\n /** Comma-separated absolute path prefixes. */\n ALLOWED_PATHS: \"SSH_ALLOWED_PATHS\",\n EXEC_TIMEOUT_MS: \"SSH_EXEC_TIMEOUT_MS\",\n CONNECT_TIMEOUT_MS: \"SSH_CONNECT_TIMEOUT_MS\",\n MAX_OUTPUT_CHARACTERS: \"SSH_MAX_OUTPUT\",\n MAX_READ_FILE_BYTES: \"SSH_MAX_READ_BYTES\",\n} as const;\n\n/** Accepted spellings for a true boolean env value. */\nexport const TRUTHY_ENV_VALUES = [\"true\", \"1\", \"yes\", \"on\"];\n\n/** Accepted spellings for a false boolean env value. */\nexport const FALSY_ENV_VALUES = [\"false\", \"0\", \"no\", \"off\"];\n","import { LOG_LEVEL_ENV } from \"@/_defs\";\n\nexport type LogLevel = \"silent\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport interface Logger {\n /** Returns a logger that appends `meta` to every record it writes. */\n child(meta: Record<string, unknown>): Logger;\n debug(message: string, meta?: Record<string, unknown>): void;\n info(message: string, meta?: Record<string, unknown>): void;\n warn(message: string, meta?: Record<string, unknown>): void;\n error(error: unknown, message: string, meta?: Record<string, unknown>): void;\n}\n\nconst LEVEL_WEIGHTS: Record<LogLevel, number> = {\n silent: 0,\n debug: 1,\n info: 2,\n warn: 3,\n error: 4,\n};\n\n/** Meta keys whose values never reach the log output. */\nconst SECRET_META_KEYS = [\"password\", \"passphrase\", \"privatekey\", \"privatekeypath\", \"secret\", \"token\"];\n\nfunction resolveThreshold(): LogLevel {\n const configured = process.env[LOG_LEVEL_ENV];\n if (configured == null) {\n return \"info\";\n }\n\n // Own-property check: a plain `LEVEL_WEIGHTS[x] == null` test walks the prototype, so\n // SSH_MCP_LOG_LEVEL=constructor would pass validation and disable all filtering.\n const normalized = configured.toLowerCase() as LogLevel;\n if (Object.hasOwn(LEVEL_WEIGHTS, normalized) == false) {\n return \"info\";\n }\n\n return normalized;\n}\n\nfunction maskMeta(meta: Record<string, unknown>): Record<string, unknown> {\n const masked: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(meta)) {\n if (SECRET_META_KEYS.includes(key.toLowerCase()) == true) {\n masked[key] = \"***\";\n continue;\n }\n\n masked[key] = value;\n }\n\n return masked;\n}\n\n/**\n * Writes to stderr only. stdout carries the MCP JSON-RPC stream over stdio transport,\n * so a single stray `console.log` corrupts the protocol and kills the session.\n */\nfunction write(level: LogLevel, message: string, meta: Record<string, unknown>): void {\n const threshold = resolveThreshold();\n if (threshold === \"silent\") {\n return;\n }\n\n if (LEVEL_WEIGHTS[level] < LEVEL_WEIGHTS[threshold]) {\n return;\n }\n\n const timestamp = new Date().toISOString();\n const masked = maskMeta(meta);\n\n let line = `${timestamp} [${level}] ${message}`;\n if (Object.keys(masked).length > 0) {\n line += ` ${JSON.stringify(masked)}`;\n }\n\n process.stderr.write(`${line}\\n`);\n}\n\nfunction createLogger(boundMeta: Record<string, unknown>): Logger {\n return {\n child(meta: Record<string, unknown>): Logger {\n return createLogger({ ...boundMeta, ...meta });\n },\n debug(message: string, meta?: Record<string, unknown>): void {\n write(\"debug\", message, { ...boundMeta, ...meta });\n },\n info(message: string, meta?: Record<string, unknown>): void {\n write(\"info\", message, { ...boundMeta, ...meta });\n },\n warn(message: string, meta?: Record<string, unknown>): void {\n write(\"warn\", message, { ...boundMeta, ...meta });\n },\n error(error: unknown, message: string, meta?: Record<string, unknown>): void {\n const errorMeta: Record<string, unknown> = { ...boundMeta, ...meta };\n if (error instanceof Error) {\n errorMeta.error_name = error.name;\n errorMeta.error_message = error.message;\n errorMeta.stack = error.stack;\n }\n else if (error != null) {\n errorMeta.error_message = String(error);\n }\n\n write(\"error\", message, errorMeta);\n },\n };\n}\n\nexport const $logger = createLogger({});\n","/** Output cut to `maxCharacters`, with a note appended when anything was dropped. */\nexport interface TruncatedText {\n text: string;\n truncated: boolean;\n}\n\n/**\n * Cuts `text` to `maxCharacters`, appending a note saying how much was dropped.\n *\n * @returns The possibly-cut text and whether anything was removed.\n */\nexport function truncateOutput(text: string, maxCharacters: number): TruncatedText {\n if (text.length <= maxCharacters) {\n return { text: text, truncated: false };\n }\n\n // Never cut between the halves of a surrogate pair: the orphaned half renders as a\n // replacement character, so an emoji at the boundary would come back corrupted.\n let cutAt = maxCharacters;\n const lastKeptCode = text.charCodeAt(cutAt - 1);\n if (lastKeptCode >= 0xd800 && lastKeptCode <= 0xdbff) {\n cutAt -= 1;\n }\n\n const droppedCharacters = text.length - cutAt;\n const kept = text.slice(0, cutAt);\n return {\n text: `${kept}\\n... [truncated ${droppedCharacters} characters of ${text.length}]`,\n truncated: true,\n };\n}\n\n/**\n * Wraps a value in single quotes for POSIX shells, escaping embedded quotes as `'\\''`.\n * Used for interpolating paths into the `cd` prefix — never for user commands, which\n * are passed through verbatim so the remote shell parses them as written.\n */\nexport function quoteShellArgument(value: string): string {\n const escaped = value.replace(/'/g, `'\\\\''`);\n return `'${escaped}'`;\n}\n\n/** Renders a byte count as `B` / `KB` / `MB` for display in tool output. */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n\n if (bytes < 1024 * 1024) {\n const kilobytes = bytes / 1024;\n return `${kilobytes.toFixed(1)} KB`;\n }\n\n const megabytes = bytes / (1024 * 1024);\n return `${megabytes.toFixed(1)} MB`;\n}\n","import os from \"node:os\";\nimport path from \"node:path\";\n\n/** Expands a leading `~` to the local home directory and returns an absolute path. */\nexport function expandHomePath(inputPath: string): string {\n let expanded = inputPath;\n if (inputPath === \"~\") {\n expanded = os.homedir();\n }\n else if (inputPath.startsWith(\"~/\") == true || inputPath.startsWith(\"~\\\\\") == true) {\n expanded = path.join(os.homedir(), inputPath.slice(2));\n }\n\n return path.resolve(expanded);\n}\n\n/** True for POSIX absolute remote paths — the only form the path guard can reason about. */\nexport function isAbsoluteRemotePath(remotePath: string): boolean {\n return remotePath.startsWith(\"/\");\n}\n\n/** Collapses `.`, `..` and duplicate slashes using POSIX rules, whatever the local OS is. */\nexport function normalizeRemotePath(remotePath: string): string {\n return path.posix.normalize(remotePath);\n}\n\n/** True when `candidate` is `allowedPrefix` itself or sits underneath it. */\nexport function isRemotePathWithin(candidate: string, allowedPrefix: string): boolean {\n const normalizedCandidate = normalizeRemotePath(candidate);\n const normalizedPrefix = normalizeRemotePath(allowedPrefix).replace(/\\/+$/, \"\");\n\n if (normalizedPrefix === \"\" || normalizedPrefix === \"/\") {\n return true;\n }\n\n if (normalizedCandidate === normalizedPrefix) {\n return true;\n }\n\n return normalizedCandidate.startsWith(`${normalizedPrefix}/`);\n}\n","import {\n BARE_REDIRECTION_OPERATOR_PATTERN,\n BENIGN_REDIRECT_PATTERN,\n COMMAND_WRAPPER_BINARIES,\n DANGEROUS_ARGUMENT_RULES,\n DANGEROUS_COMMAND_RULES,\n DANGEROUS_PIPELINE_RULES,\n NUMERIC_OPERAND_PATTERN,\n OUTPUT_REDIRECT_PATTERN,\n PRIVILEGE_ESCALATION_BINARIES,\n REDIRECTION_TOKEN_PATTERN,\n SHELL_KEYWORD_TOKENS,\n SHELL_PAYLOAD_BINARIES,\n SHELL_TOKEN_PATTERN,\n WRAPPER_VALUE_FLAGS,\n WRITE_COMMAND_BINARIES,\n WRITE_USAGE_RULES,\n} from \"@/_defs\";\nimport type { GuardVerdict, SshPolicy } from \"@/_types\";\n\n/** Membership lists as sets — these are hit once per token, per segment, per command. */\nconst WRAPPER_BINARY_SET = new Set(COMMAND_WRAPPER_BINARIES);\nconst PRIVILEGE_BINARY_SET = new Set(PRIVILEGE_ESCALATION_BINARIES);\nconst SHELL_PAYLOAD_BINARY_SET = new Set(SHELL_PAYLOAD_BINARIES);\nconst WRITE_BINARY_SET = new Set(WRITE_COMMAND_BINARIES);\nconst SHELL_KEYWORD_SET = new Set(SHELL_KEYWORD_TOKENS);\n\n/** `bash -c \"sh -c '…'\"` nests; three levels is far past anything legitimate. */\nconst MAX_INSPECTION_DEPTH = 3;\n\nconst ASSIGNMENT_TOKEN_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*=/;\n\n/** `-c` alone, or bundled into a short-flag cluster like `-lc` / `-exc`. */\nconst SHELL_COMMAND_FLAG_PATTERN = /^-[a-z]*c$/i;\n\n/**\n * Rewrites shell constructs that change how the text tokenizes but not what it runs,\n * so the rules below see the same command the remote shell will.\n *\n * - `\\` + newline is a line continuation. POSIX removes it entirely — folding it to a\n * space instead would split `r\\⏎m` into two words and hide `rm` from every rule, so it\n * is removed, and the *canonical* text is what gets executed (see `canonicalizeCommand`).\n * - `${IFS}` / `$IFS` expand to whitespace, the standard way to write a command with no\n * literal spaces in it.\n */\nexport function normalizeCommandText(command: string): string {\n return command\n .replace(/\\\\\\r?\\n/g, \"\")\n .replace(/\\$\\{IFS\\}/g, \" \")\n .replace(/\\$IFS/g, \" \");\n}\n\n/**\n * The exact text that must be sent to the remote shell.\n *\n * Validating one string and executing another is a bypass by construction: the guard saw\n * `r m -rf /` while the host ran `rm -rf /`. Callers run this, then send its result.\n */\nexport function canonicalizeCommand(command: string): string {\n return normalizeCommandText(command);\n}\n\n/**\n * Splits a command line on `;`, `&&`, `||`, `|`, `&` and newlines, leaving quoted text intact.\n * `2>&1` keeps its `&` — a `&` directly after `>` is redirection, not a background operator.\n */\nexport function splitCommandSegments(command: string): string[] {\n const segments: string[] = [];\n let current = \"\";\n let openQuote: string | null = null;\n\n for (let index = 0; index < command.length; index++) {\n const character = command[index];\n const nextCharacter = command[index + 1];\n\n if (openQuote != null) {\n current += character;\n // Single quotes take no escapes in POSIX; double quotes do.\n if (character === \"\\\\\" && openQuote === `\"` && nextCharacter != null) {\n current += nextCharacter;\n index++;\n continue;\n }\n if (character === openQuote) {\n openQuote = null;\n }\n continue;\n }\n\n if (character === \"'\" || character === `\"`) {\n openQuote = character;\n current += character;\n continue;\n }\n\n if (character === \"\\\\\") {\n current += character;\n if (nextCharacter != null) {\n current += nextCharacter;\n index++;\n }\n continue;\n }\n\n if (character === \"&\" && current.trimEnd().endsWith(\">\") == true) {\n current += character;\n continue;\n }\n\n const isDoubleOperator = (character === \"&\" && nextCharacter === \"&\") || (character === \"|\" && nextCharacter === \"|\");\n if (isDoubleOperator == true) {\n segments.push(current);\n current = \"\";\n index++;\n continue;\n }\n\n if (character === \";\" || character === \"\\n\" || character === \"|\" || character === \"&\") {\n segments.push(current);\n current = \"\";\n continue;\n }\n\n current += character;\n }\n\n segments.push(current);\n\n return segments\n .map((segment) => segment.trim())\n .filter((segment) => segment !== \"\");\n}\n\n/**\n * Drops quoted spans so `echo \"a > b\"` isn't read as a redirection.\n *\n * Quote state is checked *before* the backslash branch: POSIX single quotes take no\n * escapes, so treating `'x\\'` as an escaped quote left the span open and swallowed the\n * rest of the line — including a real `> /etc/…` redirection.\n */\nexport function stripQuotedText(segment: string): string {\n let result = \"\";\n let openQuote: string | null = null;\n\n for (let index = 0; index < segment.length; index++) {\n const character = segment[index];\n\n if (openQuote === \"'\") {\n if (character === \"'\") {\n openQuote = null;\n }\n continue;\n }\n\n if (openQuote === `\"`) {\n if (character === \"\\\\\") {\n index++;\n continue;\n }\n if (character === `\"`) {\n openQuote = null;\n }\n continue;\n }\n\n if (character === \"\\\\\") {\n index++;\n continue;\n }\n\n if (character === \"'\" || character === `\"`) {\n openQuote = character;\n continue;\n }\n\n result += character;\n }\n\n return result;\n}\n\n/** Splits a segment into shell words, keeping quoted spans as one word. */\nfunction tokenizeSegment(segment: string): string[] {\n const tokens = segment.match(SHELL_TOKEN_PATTERN);\n if (tokens == null) {\n return [];\n }\n\n return tokens;\n}\n\n/** Removes quoting so an operand can be compared against a path pattern. */\nfunction unquoteToken(token: string): string {\n if (token.includes(\"'\") == false && token.includes(`\"`) == false && token.includes(\"\\\\\") == false) {\n return token;\n }\n\n return token\n // ANSI-C quoting: `$'rm'` is the word `rm`, and dropping only the quotes would\n // leave `$rm` — a binary name no rule matches.\n .replace(/\\$'([^']*)'/g, \"$1\")\n .replace(/'([^']*)'/g, \"$1\")\n .replace(/\"([^\"]*)\"/g, \"$1\")\n .replace(/\\\\(.)/g, \"$1\");\n}\n\n/**\n * Collapses `.`, `..` and duplicate slashes in an operand before it is matched.\n *\n * `rm -rf //*`, `/./*` and `/bin/../bin` all name the same targets as the plain forms,\n * and a literal-spelling comparison would miss every one of them. Trailing glob characters\n * are preserved because the patterns match on them.\n */\nfunction normalizeOperand(operand: string): string {\n if (operand.startsWith(\"/\") == false) {\n return operand;\n }\n\n let globSuffix = \"\";\n if (operand.endsWith(\"*\") == true) {\n globSuffix = \"*\";\n }\n\n const withoutGlob = operand.slice(0, operand.length - globSuffix.length);\n const collapsed = withoutGlob.replace(/\\/{2,}/g, \"/\").replace(/\\/\\.(?=\\/|$)/g, \"/\").replace(/\\/{2,}/g, \"/\");\n\n if (collapsed === \"\") {\n return `/${globSuffix}`;\n }\n\n return `${collapsed}${globSuffix}`;\n}\n\n/**\n * Commands nested inside the text: `$(…)`, backticks, and process substitution\n * `<(…)` / `>(…)`. Each runs as a command in its own right.\n */\nexport function extractSubstitutions(command: string): string[] {\n const found: string[] = [];\n\n const nestedPattern = /(?:\\$|<|>)\\(([^()]*(?:\\([^()]*\\)[^()]*)*)\\)/g;\n let nestedMatch = nestedPattern.exec(command);\n while (nestedMatch != null) {\n found.push(nestedMatch[1]);\n nestedMatch = nestedPattern.exec(command);\n }\n\n const backtickPattern = /`([^`]*)`/g;\n let backtickMatch = backtickPattern.exec(command);\n while (backtickMatch != null) {\n found.push(backtickMatch[1]);\n backtickMatch = backtickPattern.exec(command);\n }\n\n return found.filter((substitution) => substitution.trim() !== \"\");\n}\n\nexport interface SegmentAnalysis {\n /** Wrapper binaries preceding the real command, in order — e.g. `[\"sudo\", \"env\"]`. */\n wrappers: string[];\n /** Basename of the binary that actually runs; empty when the segment has no command. */\n binary: string;\n /** Flags that follow the binary, unquoted. */\n flags: string[];\n /** Non-flag operands that follow the binary, unquoted. */\n operands: string[];\n /**\n * The segment reduced to `<basename> <args…>`, with assignment, redirection, wrapper\n * and shell-keyword prefixes removed. Rules are `^`-anchored, so they must see the\n * command at position zero — otherwise `nohup rm -rf /` and `/sbin/reboot` slide past.\n */\n normalizedText: string;\n /** Tokens of the segment, computed once and reused. */\n tokens: string[];\n}\n\n/**\n * Walks past `FOO=bar` assignments, redirection tokens, shell keywords, wrapper binaries,\n * their flags and their numeric operands (`timeout 30`) to the command that executes.\n */\nexport function analyzeSegment(segment: string): SegmentAnalysis {\n const tokens = tokenizeSegment(segment);\n const wrappers: string[] = [];\n const flags: string[] = [];\n const operands: string[] = [];\n\n let binary = \"\";\n let binaryIndex = -1;\n let expectRedirectionTarget = false;\n let expectFlagValue = false;\n\n for (let index = 0; index < tokens.length; index++) {\n const token = tokens[index];\n\n // The filename after a bare `>` / `<` is a redirection target, not a command.\n if (expectRedirectionTarget == true) {\n expectRedirectionTarget = false;\n continue;\n }\n\n // The value of a wrapper flag such as `env -u FOO` / `sudo -u deploy`.\n if (expectFlagValue == true) {\n expectFlagValue = false;\n continue;\n }\n\n if (ASSIGNMENT_TOKEN_PATTERN.test(token) == true) {\n continue;\n }\n\n if (REDIRECTION_TOKEN_PATTERN.test(token) == true) {\n if (BARE_REDIRECTION_OPERATOR_PATTERN.test(token) == true) {\n expectRedirectionTarget = true;\n }\n continue;\n }\n\n if (token.startsWith(\"-\") == true) {\n const currentWrapper = wrappers[wrappers.length - 1];\n if (currentWrapper != null) {\n const valueFlags = WRAPPER_VALUE_FLAGS[currentWrapper];\n if (valueFlags != null && valueFlags.includes(token) == true) {\n expectFlagValue = true;\n }\n }\n continue;\n }\n\n if (NUMERIC_OPERAND_PATTERN.test(token) == true && wrappers.length > 0) {\n continue;\n }\n\n const unquoted = unquoteToken(token);\n const trimmed = unquoted.replace(/^[({!]+|[)}]+$/g, \"\");\n if (SHELL_KEYWORD_SET.has(trimmed) == true || trimmed === \"\") {\n continue;\n }\n\n const basename = trimmed.split(\"/\").pop() ?? trimmed;\n if (basename === \"\") {\n continue;\n }\n\n if (WRAPPER_BINARY_SET.has(basename) == true) {\n wrappers.push(basename);\n continue;\n }\n\n binary = basename;\n binaryIndex = index;\n break;\n }\n\n if (binaryIndex >= 0) {\n for (const token of tokens.slice(binaryIndex + 1)) {\n const unquoted = unquoteToken(token);\n if (unquoted.startsWith(\"-\") == true) {\n flags.push(unquoted);\n continue;\n }\n\n operands.push(normalizeOperand(unquoted));\n }\n }\n\n // `sudo -i` has wrappers but no following command: the wrapper *is* what runs.\n if (binary === \"\" && wrappers.length > 0) {\n binary = wrappers[wrappers.length - 1];\n }\n\n let normalizedText = segment;\n if (binaryIndex >= 0) {\n // The binary is rewritten to its basename so `/sbin/reboot` matches `^reboot`.\n normalizedText = [binary, ...tokens.slice(binaryIndex + 1).map(unquoteToken)].join(\" \");\n }\n\n return {\n wrappers: wrappers,\n binary: binary,\n flags: flags,\n operands: operands,\n normalizedText: normalizedText,\n tokens: tokens,\n };\n}\n\n/**\n * Commands carried as arguments of a shell-style binary, which run in their own right:\n * the `-c \"<string>\"` form (including bundled clusters like `-lc`), and everything after\n * a `--` argv separator (`runuser -u root -- rm -rf /srv`).\n */\nfunction extractShellPayloads(analysis: SegmentAnalysis): string[] {\n if (SHELL_PAYLOAD_BINARY_SET.has(analysis.binary) == false) {\n return [];\n }\n\n const tokens = analysis.tokens;\n const payloads: string[] = [];\n\n for (let index = 0; index < tokens.length - 1; index++) {\n if (SHELL_COMMAND_FLAG_PATTERN.test(tokens[index]) == true || tokens[index] === \"--command\") {\n payloads.push(unquoteToken(tokens[index + 1]));\n }\n }\n\n const separatorIndex = tokens.indexOf(\"--\");\n if (separatorIndex >= 0 && separatorIndex < tokens.length - 1) {\n payloads.push(tokens.slice(separatorIndex + 1).map(unquoteToken).join(\" \"));\n }\n\n return payloads;\n}\n\n/**\n * Decides whether a command may run against a host.\n *\n * Ordered cheapest-to-strictest so the reported reason is the most fundamental one:\n * pipeline-wide disasters → command substitutions → then, per segment, profile deny\n * patterns → privilege escalation → always-dangerous rules → read-only rules →\n * allow-list → nested shell payloads.\n *\n * **Scope.** This is a mistake-stopper, not a sandbox. It reads the command as text, so\n * anything that hides the real operation — an interpreter one-liner, an encoded payload,\n * a tool named something else — runs unexamined, and no amount of pattern-chasing closes\n * that. The layer that actually contains an agent is the remote account's own permissions.\n */\nexport function inspectCommand(command: string, policy: SshPolicy, depth = 0): GuardVerdict {\n const normalizedCommand = normalizeCommandText(command);\n const trimmedCommand = normalizedCommand.trim();\n if (trimmedCommand === \"\") {\n return { allowed: false, reason: \"command is empty\" };\n }\n\n if (depth > MAX_INSPECTION_DEPTH) {\n return {\n allowed: false,\n reason: \"command nests shells or substitutions too deeply to screen reliably\",\n offendingText: trimmedCommand,\n };\n }\n\n for (const rule of DANGEROUS_PIPELINE_RULES) {\n if (rule.pattern.test(trimmedCommand) == true) {\n return {\n allowed: false,\n reason: `blocked as dangerous: ${rule.reason}`,\n offendingText: trimmedCommand,\n };\n }\n }\n\n for (const substitution of extractSubstitutions(trimmedCommand)) {\n const verdict = inspectCommand(substitution, policy, depth + 1);\n if (verdict.allowed == false) {\n return {\n allowed: false,\n reason: `${verdict.reason} (inside a command substitution)`,\n offendingText: substitution,\n };\n }\n }\n\n for (const segment of splitCommandSegments(trimmedCommand)) {\n const verdict = inspectSegment(segment, policy, depth);\n if (verdict.allowed == false) {\n return verdict;\n }\n }\n\n return { allowed: true };\n}\n\nfunction inspectSegment(segment: string, policy: SshPolicy, depth: number): GuardVerdict {\n const analysis = analyzeSegment(segment);\n\n // Per segment, not per command: an operator writing /^rm/ expects it to catch\n // `ls && rm -rf x`, and testing only the whole string silently would not.\n for (const pattern of policy.denyPatterns) {\n if (pattern.test(segment) == true || pattern.test(analysis.normalizedText) == true) {\n return {\n allowed: false,\n reason: `blocked by the profile's denyPatterns rule /${pattern.source}/`,\n offendingText: segment,\n };\n }\n }\n\n if (policy.allowSudo == false) {\n const escalation = [...analysis.wrappers, analysis.binary]\n .find((name) => PRIVILEGE_BINARY_SET.has(name) == true);\n if (escalation != null) {\n return {\n allowed: false,\n reason: `privilege escalation via '${escalation}' is disabled for this profile (set allowSudo: true to permit it)`,\n offendingText: segment,\n };\n }\n }\n\n // The raw segment is only re-tested when normalization actually changed something —\n // it carries redirections (`> /dev/sda`) that the normalized form drops.\n const shouldTestRawSegment = analysis.normalizedText !== segment;\n\n for (const rule of DANGEROUS_COMMAND_RULES) {\n const matched = rule.pattern.test(analysis.normalizedText) == true\n || (shouldTestRawSegment == true && rule.pattern.test(segment) == true);\n if (matched == true) {\n return {\n allowed: false,\n reason: `blocked as dangerous: ${rule.reason}`,\n offendingText: segment,\n };\n }\n }\n\n for (const rule of DANGEROUS_ARGUMENT_RULES) {\n if (rule.binaries.includes(analysis.binary) == false) {\n continue;\n }\n\n if (rule.requiredFlagPattern != null) {\n const hasRequiredFlag = analysis.flags.some((flag) => rule.requiredFlagPattern?.test(flag) == true);\n if (hasRequiredFlag == false) {\n continue;\n }\n }\n\n const offendingOperand = analysis.operands.find((operand) => rule.argumentPattern.test(operand) == true);\n if (offendingOperand != null) {\n return {\n allowed: false,\n reason: `blocked as dangerous: ${rule.reason}`,\n offendingText: `${analysis.binary} … ${offendingOperand}`,\n };\n }\n }\n\n if (policy.readonly == true) {\n const readonlyVerdict = inspectReadOnly(segment, analysis, shouldTestRawSegment);\n if (readonlyVerdict.allowed == false) {\n return readonlyVerdict;\n }\n }\n\n if (policy.allowCommands.length > 0) {\n // An empty binary means the segment is only a redirection (`> /etc/cron.d/x`),\n // which writes a file without naming a command — it must not skip the allow-list.\n if (analysis.binary === \"\") {\n return {\n allowed: false,\n reason: `this profile only permits ${policy.allowCommands.join(\", \")}, and this segment runs no listed command`,\n offendingText: segment,\n };\n }\n\n if (policy.allowCommands.includes(analysis.binary) == false) {\n return {\n allowed: false,\n reason: `'${analysis.binary}' is not in this profile's allowCommands list (${policy.allowCommands.join(\", \")})`,\n offendingText: segment,\n };\n }\n }\n\n for (const payload of extractShellPayloads(analysis)) {\n const verdict = inspectCommand(payload, policy, depth + 1);\n if (verdict.allowed == false) {\n return {\n allowed: false,\n reason: `${verdict.reason} (inside a '${analysis.binary} -c' payload)`,\n offendingText: payload,\n };\n }\n }\n\n return { allowed: true };\n}\n\nfunction inspectReadOnly(segment: string, analysis: SegmentAnalysis, shouldTestRawSegment: boolean): GuardVerdict {\n if (WRITE_BINARY_SET.has(analysis.binary) == true) {\n return {\n allowed: false,\n reason: `profile is read-only and '${analysis.binary}' can modify the host`,\n offendingText: segment,\n };\n }\n\n for (const rule of WRITE_USAGE_RULES) {\n const matched = rule.pattern.test(analysis.normalizedText) == true\n || (shouldTestRawSegment == true && rule.pattern.test(segment) == true);\n if (matched == true) {\n return {\n allowed: false,\n reason: `profile is read-only: ${rule.reason}`,\n offendingText: segment,\n };\n }\n }\n\n const withoutQuotes = stripQuotedText(segment);\n const withoutBenignRedirects = withoutQuotes.replace(BENIGN_REDIRECT_PATTERN, \"\");\n if (OUTPUT_REDIRECT_PATTERN.test(withoutBenignRedirects) == true) {\n return {\n allowed: false,\n reason: \"profile is read-only and the command redirects output into a file\",\n offendingText: segment,\n };\n }\n\n return { allowed: true };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport { PROTECTED_LOCAL_PATH_RULES, UNSAFE_PATH_CHARACTER_PATTERN } from \"@/_defs\";\nimport { $logger, isAbsoluteRemotePath, isRemotePathWithin, normalizeRemotePath } from \"@/_libs\";\nimport type { GuardVerdict, SshPolicy } from \"@/_types\";\n\nexport type RemotePathAccess = \"read\" | \"write\";\n\n/**\n * Decides whether a file tool may touch a remote path.\n *\n * With `allowedPaths` set, only absolute paths are accepted: a relative path resolves\n * against the SFTP session's own working directory, which the guard cannot see, so it\n * could escape the allow-list without any way to detect it here.\n *\n * Symlinks on the remote side are not resolved — the guard has no view of that\n * filesystem. `allowedPaths` therefore bounds *names*, not inodes.\n */\nexport function inspectRemotePath(\n remotePath: string,\n policy: SshPolicy,\n access: RemotePathAccess\n): GuardVerdict {\n const trimmedPath = remotePath.trim();\n if (trimmedPath === \"\") {\n return { allowed: false, reason: \"path is empty\" };\n }\n\n if (access === \"write\" && policy.readonly == true) {\n return {\n allowed: false,\n reason: \"profile is read-only, remote writes are not permitted\",\n offendingText: trimmedPath,\n };\n }\n\n if (policy.allowedPaths.length === 0) {\n return { allowed: true };\n }\n\n if (isAbsoluteRemotePath(trimmedPath) == false) {\n return {\n allowed: false,\n reason: `this profile restricts file access to ${policy.allowedPaths.join(\", \")}, so the path must be absolute`,\n offendingText: trimmedPath,\n };\n }\n\n const normalizedPath = normalizeRemotePath(trimmedPath);\n const matched = policy.allowedPaths.some((allowedPath) => isRemotePathWithin(normalizedPath, allowedPath) == true);\n if (matched == false) {\n return {\n allowed: false,\n reason: `path is outside this profile's allowedPaths (${policy.allowedPaths.join(\", \")})`,\n offendingText: normalizedPath,\n };\n }\n\n return { allowed: true };\n}\n\n/**\n * Resolves symlinks so the guard compares the file that will actually be touched.\n *\n * A lexical `path.resolve` is not enough: `~/notes.txt` symlinked to `~/.ssh/id_ed25519`\n * matches no rule by name, and both `fastPut` and `fastGet` follow the link. For a path\n * that does not exist yet (the normal download case) the parent directory is resolved\n * instead, which catches a symlinked *directory*.\n */\nfunction toRealPath(inputPath: string): string {\n const _logger = $logger.child({ context: \"toRealPath\" });\n\n try {\n return fs.realpathSync.native(inputPath);\n }\n catch (ex) {\n // Expected for a download destination that does not exist yet, so this is not an\n // error — but it must not pass unrecorded, since the fallback guards less.\n _logger.debug(\"path does not resolve, falling back to its parent directory\", {\n reason: ex instanceof Error ? ex.name : \"unknown\",\n });\n }\n\n try {\n const parentRealPath = fs.realpathSync.native(path.dirname(inputPath));\n return path.join(parentRealPath, path.basename(inputPath));\n }\n catch (ex) {\n _logger.debug(\"parent directory does not resolve either, comparing lexically\", {\n reason: ex instanceof Error ? ex.name : \"unknown\",\n });\n return path.resolve(inputPath);\n }\n}\n\n/** Path form the protected-path rules are written against. */\nfunction toComparablePath(inputPath: string): string {\n return toRealPath(inputPath).replace(/\\\\/g, \"/\");\n}\n\n/**\n * Decides whether a file tool may touch a path on the machine running this server.\n *\n * Separate from the remote guard because the threat is inverted: here the danger is\n * reading the operator's own credentials out (upload) or overwriting the files that\n * define the guards themselves (download).\n *\n * @param resolvedLocalPath Absolute path, already `~`-expanded.\n * @param extraProtectedPaths Runtime-known paths to protect, such as the loaded config file.\n */\nexport function inspectLocalPath(\n resolvedLocalPath: string,\n access: RemotePathAccess,\n extraProtectedPaths: string[] = []\n): GuardVerdict {\n const trimmedPath = resolvedLocalPath.trim();\n if (trimmedPath === \"\") {\n return { allowed: false, reason: \"local path is empty\" };\n }\n\n const comparablePath = toComparablePath(trimmedPath);\n\n for (const rule of PROTECTED_LOCAL_PATH_RULES) {\n if (rule.pattern.test(comparablePath) == true) {\n let verb = \"read from\";\n if (access === \"write\") {\n verb = \"written to\";\n }\n\n return {\n allowed: false,\n reason: `local path is protected and cannot be ${verb}: ${rule.reason}`,\n offendingText: trimmedPath,\n };\n }\n }\n\n for (const protectedPath of extraProtectedPaths) {\n if (protectedPath === \"\") {\n continue;\n }\n\n if (comparablePath.toLowerCase() === toComparablePath(protectedPath).toLowerCase()) {\n return {\n allowed: false,\n reason: \"local path is this server's own configuration file\",\n offendingText: trimmedPath,\n };\n }\n }\n\n return { allowed: true };\n}\n\n/**\n * Decides whether a `cwd` argument is safe to interpolate into the generated `cd` prefix.\n *\n * `cwd` never reaches the command guard — it is not a command — yet it lands in the same\n * remote shell script. Without this check, `cwd: '/tmp\"; rm -rf /; #'` executes with every\n * command guard bypassed.\n */\nexport function inspectWorkingDirectory(cwd: string): GuardVerdict {\n const trimmedCwd = cwd.trim();\n if (trimmedCwd === \"\") {\n return { allowed: true };\n }\n\n const unsafeMatch = UNSAFE_PATH_CHARACTER_PATTERN.exec(trimmedCwd);\n if (unsafeMatch != null) {\n const displayCharacter = unsafeMatch[0]\n .replace(/\\n/, \"\\\\n\")\n .replace(/\\r/, \"\\\\r\")\n .replace(/\\t/, \"\\\\t\");\n return {\n allowed: false,\n reason: `cwd contains the shell metacharacter '${displayCharacter}', which is not allowed in a directory argument`,\n offendingText: trimmedCwd,\n };\n }\n\n return { allowed: true };\n}\n\n/** Warns once when a profile's own settings make its guards inert. */\nexport function warnOnInertPolicy(profileName: string, policy: SshPolicy): void {\n if (policy.readonly == true || policy.allowCommands.length > 0 || policy.denyPatterns.length > 0) {\n return;\n }\n\n const _logger = $logger.child({ context: \"warnOnInertPolicy\", profile: profileName });\n _logger.debug(\"profile runs with catastrophe-only guards; remote account permissions are the real boundary\");\n}\n","import type { GuardVerdict } from \"@/_types\";\n\n/**\n * Thrown when a guard refuses an operation.\n *\n * A distinct class because callers genuinely branch on it: the tool layer renders a\n * rejection with `formatGuardRejection` and marks it a policy decision, while any other\n * error is an operational failure worth retrying. It carries the verdict so that\n * rendering needs no string parsing.\n */\nexport class GuardRejectionError extends Error {\n constructor(public readonly verdict: GuardVerdict) {\n super(verdict.reason ?? \"rejected by the host profile's guard policy\");\n this.name = \"GuardRejectionError\";\n }\n}\n","import { createHash } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport { StringDecoder } from \"node:string_decoder\";\n\nimport ssh2 from \"ssh2\";\nimport type { ConnectConfig, SFTPWrapper } from \"ssh2\";\n\nimport { CWD_MARKER, KEEPALIVE_INTERVAL_MS } from \"@/_defs\";\nimport { $logger, quoteShellArgument, truncateOutput } from \"@/_libs\";\nimport type { SshExecResult, SshHostProfile } from \"@/_types\";\nimport { GuardRejectionError, canonicalizeCommand, inspectCommand, inspectWorkingDirectory } from \"@/modules/guard\";\n\nconst { Client } = ssh2;\n\n/** Stops runaway output from filling the heap before truncation can happen. */\nconst OUTPUT_HARD_CAP_MULTIPLIER = 4;\n\n/** Key file contents by absolute path — immutable for the process lifetime. */\nconst PRIVATE_KEY_CACHE = new Map<string, Buffer>();\n\nexport interface SshExecOptions {\n command: string;\n /** Directory to `cd` into first; the login shell's default is used when absent. */\n cwd?: string;\n timeoutMs: number;\n maxOutputCharacters: number;\n /** Appends a `$PWD` marker so a session can follow `cd` between commands. */\n trackCwd: boolean;\n}\n\n/** Windows OpenSSH agent pipe — ssh2 accepts it wherever a socket path is expected. */\nconst WINDOWS_AGENT_PIPE = \"\\\\\\\\.\\\\pipe\\\\openssh-ssh-agent\";\n\nfunction resolveAgentPath(): string | undefined {\n const authSocket = process.env.SSH_AUTH_SOCK;\n if (authSocket != null && authSocket !== \"\") {\n return authSocket;\n }\n\n if (process.platform === \"win32\") {\n return WINDOWS_AGENT_PIPE;\n }\n\n return undefined;\n}\n\n/**\n * Reads a private key, caching by path.\n *\n * Without the cache every one-off tool call re-read the same file synchronously, stalling\n * the event loop for every other in-flight call.\n *\n * @throws {Error} If the file cannot be read. The path is deliberately kept out of the\n * message — it reaches the model verbatim, and the rest of the codebase\n * (logger masking, `toHostSummary`) treats it as a secret.\n */\nfunction readPrivateKey(profile: SshHostProfile, keyPath: string): Buffer {\n const cached = PRIVATE_KEY_CACHE.get(keyPath);\n if (cached != null) {\n return cached;\n }\n\n try {\n const contents = fs.readFileSync(keyPath);\n PRIVATE_KEY_CACHE.set(keyPath, contents);\n return contents;\n }\n catch (ex) {\n const _logger = $logger.child({ context: \"readPrivateKey\", profile: profile.name });\n _logger.error(ex, \"cannot read the profile's private key file\");\n throw new Error(`cannot read the private key configured for profile '${profile.name}' (see the server log for the path)`);\n }\n}\n\n/** OpenSSH-style fingerprint — the same string `ssh-keyscan` and `ssh` itself print. */\nexport function toHostKeyFingerprint(hostKey: Buffer): string {\n const digest = createHash(\"sha256\").update(hostKey).digest(\"base64\").replace(/=+$/, \"\");\n return `SHA256:${digest}`;\n}\n\n/**\n * Builds the host key check.\n *\n * ssh2 accepts *any* host key when no verifier is supplied, so without this a\n * man-in-the-middle — or a rebuilt server presenting a new key — is indistinguishable\n * from the real host. Pinning stays opt-in (`hostKeyFingerprint`) to match the permissive\n * defaults, but the fingerprint is always logged on first connect so it can be copied\n * into the profile.\n */\nfunction buildHostVerifier(\n profile: SshHostProfile,\n onHostKeySeen: (fingerprint: string) => void\n): (hostKey: Buffer) => boolean {\n return (hostKey: Buffer) => {\n const fingerprint = toHostKeyFingerprint(hostKey);\n onHostKeySeen(fingerprint);\n\n const _logger = $logger.child({ context: \"hostVerifier\", profile: profile.name, host: profile.host });\n\n if (profile.hostKeyFingerprint == null) {\n _logger.info(\"host key accepted unpinned; add hostKeyFingerprint to the profile to pin it\", {\n host_key_fingerprint: fingerprint,\n });\n return true;\n }\n\n if (profile.hostKeyFingerprint === fingerprint) {\n _logger.debug(\"host key matches the pinned fingerprint\");\n return true;\n }\n\n _logger.error(null, \"host key does not match the pinned fingerprint\", {\n expected: profile.hostKeyFingerprint,\n actual: fingerprint,\n });\n return false;\n };\n}\n\n/** Profile → ssh2 connect options. */\nfunction buildConnectConfig(\n profile: SshHostProfile,\n onHostKeySeen: (fingerprint: string) => void\n): ConnectConfig {\n const connectConfig: ConnectConfig = {\n host: profile.host,\n port: profile.port,\n username: profile.username,\n readyTimeout: profile.policy.connectTimeoutMs,\n keepaliveInterval: KEEPALIVE_INTERVAL_MS,\n hostVerifier: buildHostVerifier(profile, onHostKeySeen),\n };\n\n if (profile.privateKeyPath != null) {\n connectConfig.privateKey = readPrivateKey(profile, profile.privateKeyPath);\n }\n else if (profile.privateKey != null) {\n connectConfig.privateKey = profile.privateKey;\n }\n\n if (profile.passphrase != null) {\n connectConfig.passphrase = profile.passphrase;\n }\n\n if (profile.password != null) {\n connectConfig.password = profile.password;\n }\n\n // No key and no password — fall back to the running SSH agent, which is how most\n // interactive setups already authenticate.\n if (connectConfig.privateKey == null && connectConfig.password == null) {\n connectConfig.agent = resolveAgentPath();\n }\n\n return connectConfig;\n}\n\n/**\n * Wraps the user command so the remote shell reports where it ended up.\n *\n * `$?` is captured before the marker is printed and replayed via `exit`, so the exit\n * status the caller sees is the command's, not `printf`'s.\n *\n * `cwd` appears exactly once, inside `quoteShellArgument`. It must never be interpolated\n * anywhere else — an earlier version echoed it into a double-quoted diagnostic, which let\n * `cwd: '/x\"; rm -rf /; #'` run arbitrary commands with every guard bypassed. The failure\n * message is therefore a fixed string.\n */\nexport function buildRemoteCommand(command: string, cwd: string | undefined, trackCwd: boolean): string {\n const lines: string[] = [];\n\n if (cwd != null && cwd !== \"\") {\n const quotedCwd = quoteShellArgument(cwd);\n lines.push(`cd ${quotedCwd} 2>/dev/null || { echo 'akms-ssh: cannot enter the requested working directory' >&2; exit 1; }`);\n }\n\n lines.push(command);\n\n if (trackCwd == true) {\n lines.push(\"__akms_exit=$?\");\n lines.push(`printf '\\\\n${CWD_MARKER}%s' \"$PWD\"`);\n lines.push(\"exit $__akms_exit\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Splits the trailing `$PWD` marker off stdout. */\nexport function extractCwdMarker(stdout: string): { output: string; cwd?: string } {\n const markerIndex = stdout.lastIndexOf(CWD_MARKER);\n if (markerIndex < 0) {\n return { output: stdout };\n }\n\n // First line only: `$PWD` is a single line, so anything past a newline is not the\n // directory and must not end up in the `cd` prefix of the next command.\n const markerPayload = stdout.slice(markerIndex + CWD_MARKER.length);\n const cwd = (markerPayload.split(\"\\n\")[0] ?? \"\").trim();\n\n let output = stdout.slice(0, markerIndex);\n if (output.endsWith(\"\\n\") == true) {\n output = output.slice(0, -1);\n }\n\n if (cwd === \"\") {\n return { output: output };\n }\n\n return { output: output, cwd: cwd };\n}\n\n/**\n * One ssh2 client bound to a profile, plus the exec / SFTP operations run over it.\n *\n * This class is the chokepoint: it holds the profile, so it applies the command guard\n * itself rather than trusting each caller to remember. Enforcement in the tool handlers\n * was one forgotten line away from shipping an unscreened command — and one such caller\n * (the `ssh_connect` probe) already existed.\n */\nexport class SshConnection {\n private client: ssh2.Client | null = null;\n private pendingClient: ssh2.Client | null = null;\n private connecting: Promise<void> | null = null;\n private disposed = false;\n /** Set when the peer closed a previously established connection. */\n private droppedAfterReady = false;\n private observedFingerprint: string | null = null;\n\n constructor(public readonly profile: SshHostProfile) {\n }\n\n get isConnected(): boolean {\n return this.client != null;\n }\n\n /** Host key the server presented, once a handshake has been attempted. */\n get hostKeyFingerprint(): string | null {\n return this.observedFingerprint;\n }\n\n /** True when a connection was established and then lost, so shell state is gone. */\n get wasDropped(): boolean {\n return this.droppedAfterReady;\n }\n\n /**\n * Opens the connection, or joins the in-flight attempt when one is already running.\n *\n * @throws {Error} If the connection was closed, authentication fails, the host is\n * unreachable, or the handshake times out.\n */\n async connect(): Promise<void> {\n if (this.disposed == true) {\n throw new Error(`ssh connection for '${this.profile.name}' has been closed; open a new session`);\n }\n\n if (this.client != null) {\n return;\n }\n\n if (this.connecting != null) {\n await this.connecting;\n return;\n }\n\n const _logger = $logger.child({\n context: \"SshConnection.connect\",\n profile: this.profile.name,\n host: this.profile.host,\n port: this.profile.port,\n username: this.profile.username,\n });\n\n const connectConfig = buildConnectConfig(this.profile, (fingerprint) => {\n this.observedFingerprint = fingerprint;\n });\n\n this.connecting = new Promise<void>((resolve, reject) => {\n const client = new Client();\n this.pendingClient = client;\n let settled = false;\n\n // One permanent 'error' listener, installed before connect() and never\n // removed. Registering it with `once` left the client listener-less after the\n // first error, and ssh2 emits 'error' again while the socket tears down —\n // an unhandled 'error' event takes down the whole server process.\n client.on(\"error\", (error: Error) => {\n if (settled == false) {\n settled = true;\n this.pendingClient = null;\n client.destroy();\n reject(error);\n return;\n }\n\n _logger.error(error, \"ssh connection error after ready\");\n });\n\n client.on(\"close\", () => {\n if (this.client === client) {\n _logger.debug(\"ssh connection closed by the peer\");\n this.client = null;\n this.droppedAfterReady = true;\n }\n });\n\n client.once(\"ready\", () => {\n if (settled == true) {\n return;\n }\n settled = true;\n this.pendingClient = null;\n\n // disconnect() may have run while the handshake was in flight; adopting\n // the client now would leak a live connection nothing can ever close.\n if (this.disposed == true) {\n client.destroy();\n reject(new Error(`ssh connection for '${this.profile.name}' was closed during the handshake`));\n return;\n }\n\n this.client = client;\n resolve();\n });\n\n client.connect(connectConfig);\n });\n\n try {\n await this.connecting;\n _logger.info(\"ssh connection established\");\n }\n catch (ex) {\n _logger.error(ex, \"ssh connection failed\");\n\n let detail = String(ex);\n if (ex instanceof Error) {\n detail = ex.message;\n }\n\n throw new Error(`ssh connect failed for '${this.profile.name}' (${this.profile.username}@${this.profile.host}:${this.profile.port}): ${detail}`);\n }\n finally {\n this.connecting = null;\n }\n }\n\n /**\n * Screens a command against this profile's policy, then runs it on its own channel.\n *\n * The canonical form is what gets screened *and* what gets sent — validating one\n * string while executing another is a bypass by construction.\n *\n * @throws {GuardRejectionError} If the policy refuses the command or the cwd.\n * @throws {Error} If the connection is closed or the channel cannot be opened.\n */\n async exec(options: SshExecOptions): Promise<SshExecResult> {\n const canonicalCommand = canonicalizeCommand(options.command);\n\n const verdict = inspectCommand(canonicalCommand, this.profile.policy);\n if (verdict.allowed == false) {\n throw new GuardRejectionError(verdict);\n }\n\n if (options.cwd != null) {\n const cwdVerdict = inspectWorkingDirectory(options.cwd);\n if (cwdVerdict.allowed == false) {\n throw new GuardRejectionError(cwdVerdict);\n }\n }\n\n await this.connect();\n\n const client = this.client;\n if (client == null) {\n throw new Error(`ssh connection for '${this.profile.name}' is not open`);\n }\n\n const _logger = $logger.child({\n context: \"SshConnection.exec\",\n profile: this.profile.name,\n cwd: options.cwd,\n });\n\n const remoteCommand = buildRemoteCommand(canonicalCommand, options.cwd, options.trackCwd);\n const hardCap = options.maxOutputCharacters * OUTPUT_HARD_CAP_MULTIPLIER;\n const startedAt = Date.now();\n\n const raw = await new Promise<{\n stdout: string;\n stderr: string;\n exitCode: number | null;\n signal?: string;\n timedOut: boolean;\n }>((resolve, reject) => {\n client.exec(remoteCommand, (error, channel) => {\n if (error != null) {\n reject(error);\n return;\n }\n\n let stdout = \"\";\n let stderr = \"\";\n let exitCode: number | null = null;\n let signal: string | undefined = undefined;\n let timedOut = false;\n let settled = false;\n // Latch: channel.close() is a round trip, so packets keep arriving after\n // the cap trips. Without it each one re-logged and re-grew the string.\n let capExceeded = false;\n\n // One decoder per stream: a multi-byte character split across two SSH\n // packets decodes to U+FFFD if each chunk is converted on its own.\n const stdoutDecoder = new StringDecoder(\"utf8\");\n const stderrDecoder = new StringDecoder(\"utf8\");\n\n const timeoutTimer = setTimeout(() => {\n timedOut = true;\n _logger.warn(\"command timed out, closing the channel\", { timeout_ms: options.timeoutMs });\n channel.close();\n }, options.timeoutMs);\n timeoutTimer.unref();\n\n // Only 'close' settles the promise. 'end' fires on CHANNEL_EOF, which the\n // remote may send before the separate exit-status request arrives — settling\n // there reports a successful command as `exit code: none (killed)`.\n const finish = (): void => {\n if (settled == true) {\n return;\n }\n settled = true;\n clearTimeout(timeoutTimer);\n\n stdout += stdoutDecoder.end();\n stderr += stderrDecoder.end();\n\n resolve({ stdout: stdout, stderr: stderr, exitCode: exitCode, signal: signal, timedOut: timedOut });\n };\n\n channel.on(\"data\", (chunk: Buffer) => {\n if (capExceeded == true) {\n return;\n }\n\n stdout += stdoutDecoder.write(chunk);\n if (stdout.length > hardCap) {\n capExceeded = true;\n _logger.warn(\"stdout exceeded the hard cap, closing the channel\", { hard_cap: hardCap });\n channel.close();\n }\n });\n\n channel.stderr.on(\"data\", (chunk: Buffer) => {\n if (capExceeded == true) {\n return;\n }\n\n stderr += stderrDecoder.write(chunk);\n if (stderr.length > hardCap) {\n capExceeded = true;\n channel.close();\n }\n });\n\n channel.on(\"exit\", (code: number | null, exitSignal?: string) => {\n exitCode = code;\n signal = exitSignal;\n });\n\n channel.on(\"close\", finish);\n channel.on(\"error\", (channelError: Error) => {\n clearTimeout(timeoutTimer);\n if (settled == true) {\n return;\n }\n settled = true;\n reject(channelError);\n });\n\n // Send EOF on the remote stdin straight away. Nothing will ever be written\n // to it, and a command that reads — a `sudo` password prompt, an apt\n // confirmation, `ssh-keygen` — would otherwise sit there until the timeout\n // fires. With stdin closed it fails in milliseconds with a usable message.\n //\n // `eof()`, not `end()`: end() also closes the channel, which loses the\n // exit-status request the server sends afterwards.\n channel.eof();\n });\n });\n\n // Only parse the marker when this call asked for it — otherwise output that merely\n // contains the marker text would be silently cut at that point.\n let output = raw.stdout;\n let cwd: string | undefined = undefined;\n if (options.trackCwd == true) {\n const parsed = extractCwdMarker(raw.stdout);\n output = parsed.output;\n cwd = parsed.cwd;\n }\n\n const truncatedStdout = truncateOutput(output, options.maxOutputCharacters);\n const truncatedStderr = truncateOutput(raw.stderr, options.maxOutputCharacters);\n\n const result: SshExecResult = {\n stdout: truncatedStdout.text,\n stderr: truncatedStderr.text,\n exitCode: raw.exitCode,\n timedOut: raw.timedOut,\n truncated: truncatedStdout.truncated == true || truncatedStderr.truncated == true,\n durationMs: Date.now() - startedAt,\n };\n\n if (raw.signal != null) {\n result.signal = raw.signal;\n }\n\n if (cwd != null) {\n result.cwd = cwd;\n }\n\n _logger.debug(\"command finished\", {\n exit_code: result.exitCode,\n duration_ms: result.durationMs,\n timed_out: result.timedOut,\n });\n\n return result;\n }\n\n /**\n * Opens an SFTP channel, hands it to `handler`, and closes it afterwards.\n *\n * A channel per operation costs one round trip but keeps a broken transfer from\n * poisoning later ones — SFTP channels do not recover from a mid-stream error.\n *\n * The channel's own `error` event is wired into the returned promise: ssh2 strips its\n * setup listeners before handing the wrapper over, so an unhandled SFTP protocol error\n * would otherwise crash the process rather than fail this one call.\n *\n * @throws {Error} If the SFTP subsystem cannot be started or the channel errors.\n */\n async withSftp<T>(handler: (sftp: SFTPWrapper) => Promise<T>): Promise<T> {\n await this.connect();\n\n const client = this.client;\n if (client == null) {\n throw new Error(`ssh connection for '${this.profile.name}' is not open`);\n }\n\n const sftp = await new Promise<SFTPWrapper>((resolve, reject) => {\n client.sftp((error, sftpWrapper) => {\n if (error != null) {\n reject(error);\n return;\n }\n\n resolve(sftpWrapper);\n });\n });\n\n return await new Promise<T>((resolve, reject) => {\n let settled = false;\n\n const finish = (settle: () => void): void => {\n if (settled == true) {\n return;\n }\n settled = true;\n\n try {\n sftp.end();\n }\n catch (ex) {\n const _logger = $logger.child({ context: \"SshConnection.withSftp\", profile: this.profile.name });\n _logger.error(ex, \"failed to close the sftp channel\");\n }\n\n settle();\n };\n\n sftp.on(\"error\", (error: Error) => {\n finish(() => {\n reject(error);\n });\n });\n\n handler(sftp).then(\n (value) => {\n finish(() => {\n resolve(value);\n });\n },\n (error: unknown) => {\n finish(() => {\n reject(error);\n });\n }\n );\n });\n }\n\n /** Closes the connection for good; a disposed connection will not re-dial. */\n disconnect(): void {\n this.disposed = true;\n\n // A handshake still in flight would otherwise complete and install its client on\n // an object nothing holds a reference to any more.\n if (this.pendingClient != null) {\n this.pendingClient.destroy();\n this.pendingClient = null;\n }\n\n if (this.client == null) {\n return;\n }\n\n this.client.end();\n this.client = null;\n }\n}\n","import { setInterval, clearInterval } from \"node:timers\";\n\nimport { SESSION_IDLE_TIMEOUT_MS, SESSION_SWEEP_INTERVAL_MS } from \"@/_defs\";\nimport { $logger } from \"@/_libs\";\nimport type { SshExecResult, SshHostProfile, SshSessionInfo } from \"@/_types\";\nimport { inspectWorkingDirectory } from \"@/modules/guard\";\n\nimport { SshConnection } from \"./ssh-connection\";\n\n/** Ceiling on concurrently open sessions, so a runaway loop can't exhaust file descriptors. */\nconst MAX_OPEN_SESSIONS = 32;\n\n/** A connection plus the shell state (working directory) carried across commands. */\nexport class SshSession {\n /** Empty until the first command reports `$PWD`; then the real remote path. */\n cwd: string;\n lastUsedAt: Date;\n execCount = 0;\n\n readonly openedAt = new Date();\n\n /** Tail of the serialized operation chain; see `runExclusive`. */\n private operationChain: Promise<unknown> = Promise.resolve();\n private activeOperationCount = 0;\n\n constructor(\n public readonly sessionId: string,\n public readonly connection: SshConnection\n ) {\n this.cwd = connection.profile.defaultCwd ?? \"\";\n this.lastUsedAt = new Date();\n }\n\n get profile(): SshHostProfile {\n return this.connection.profile;\n }\n\n /** True while an operation is running, so the idle sweeper leaves it alone. */\n get isBusy(): boolean {\n return this.activeOperationCount > 0;\n }\n\n /** Marks the session as in use. */\n touch(): void {\n this.lastUsedAt = new Date();\n }\n\n /**\n * Runs `operation` with exclusive use of this session.\n *\n * Serialized because `cwd` is read-modify-write across a network round trip: two\n * concurrent calls both read the old directory, and the one that finishes second\n * writes it back — silently undoing the other's `cd`. Bracketing with `touch()` also\n * keeps the idle sweeper off a session that is mid-transfer.\n */\n async runExclusive<T>(operation: (connection: SshConnection) => Promise<T>): Promise<T> {\n const previous = this.operationChain;\n\n let releaseChain: () => void = () => {\n // Replaced below; assigned here so the type is not nullable.\n };\n this.operationChain = new Promise<void>((resolve) => {\n releaseChain = resolve;\n });\n\n await previous.catch(() => {\n // A failed predecessor must not poison the queue for later callers.\n });\n\n this.activeOperationCount += 1;\n this.touch();\n\n try {\n return await operation(this.connection);\n }\n finally {\n this.activeOperationCount -= 1;\n this.touch();\n releaseChain();\n }\n }\n\n /**\n * Runs a command in this session's working directory and adopts wherever it ended up,\n * so a `cd` in one call is still in effect on the next.\n *\n * Passing `cwd` runs this command elsewhere *and* moves the session there — same\n * result as prefixing `cd <cwd> &&`, which is what a shell user would expect.\n *\n * @throws {Error} If the connection was dropped since the session opened. A silent\n * re-dial would hand back a fresh login shell while the model still\n * believes it holds the old one — environment, sudo cache and\n * background jobs all gone with no signal.\n */\n async exec(command: string, options?: { cwd?: string; timeoutMs?: number }): Promise<SshExecResult> {\n if (this.connection.wasDropped == true) {\n throw new Error(`session ${this.sessionId} lost its connection to ${this.profile.host}; its shell state is gone — open a new session with ssh_connect`);\n }\n\n const policy = this.profile.policy;\n const targetCwd = options?.cwd ?? this.cwd;\n\n return await this.runExclusive(async (connection) => {\n const result = await connection.exec({\n command: command,\n cwd: targetCwd,\n timeoutMs: options?.timeoutMs ?? policy.execTimeoutMs,\n maxOutputCharacters: policy.maxOutputCharacters,\n trackCwd: true,\n });\n\n if (result.cwd != null && result.cwd !== \"\") {\n // The reported `$PWD` becomes the `cd` argument of the next command, so it\n // goes through the same metacharacter check as a caller-supplied cwd.\n const verdict = inspectWorkingDirectory(result.cwd);\n if (verdict.allowed == true) {\n this.cwd = result.cwd;\n }\n else {\n const _logger = $logger.child({ context: \"SshSession.exec\", session_id: this.sessionId });\n _logger.warn(\"remote working directory contains unsafe characters, keeping the previous cwd\", {\n reported_cwd: result.cwd,\n });\n }\n }\n\n this.execCount += 1;\n return result;\n });\n }\n\n toInfo(): SshSessionInfo {\n let displayCwd = this.cwd;\n if (displayCwd === \"\") {\n displayCwd = \"(login default)\";\n }\n\n return {\n sessionId: this.sessionId,\n profileName: this.profile.name,\n host: this.profile.host,\n username: this.profile.username,\n cwd: displayCwd,\n openedAt: this.openedAt.toISOString(),\n lastUsedAt: this.lastUsedAt.toISOString(),\n execCount: this.execCount,\n };\n }\n}\n\n/** Owns every open session: creation, lookup, idle expiry and shutdown. */\nexport class SshSessionManager {\n private readonly sessions = new Map<string, SshSession>();\n private sequence = 0;\n private pendingOpenCount = 0;\n private sweepTimer: NodeJS.Timeout | null = null;\n\n /**\n * Opens a connection and registers it as a session.\n *\n * `pendingOpenCount` reserves the slot across the `await`: checking `sessions.size`\n * alone let N concurrent calls all observe the same pre-connect count and blow past\n * the ceiling together.\n *\n * @throws {Error} If the session ceiling is reached or the connection fails.\n */\n async open(profile: SshHostProfile): Promise<SshSession> {\n if (this.sessions.size + this.pendingOpenCount >= MAX_OPEN_SESSIONS) {\n throw new Error(`too many open ssh sessions (${MAX_OPEN_SESSIONS}), close some with ssh_disconnect first`);\n }\n\n this.sequence += 1;\n const sessionId = `${profile.name}#${this.sequence}`;\n\n const connection = new SshConnection(profile);\n\n this.pendingOpenCount += 1;\n try {\n await connection.connect();\n }\n finally {\n this.pendingOpenCount -= 1;\n }\n\n const session = new SshSession(sessionId, connection);\n this.sessions.set(sessionId, session);\n\n const _logger = $logger.child({ context: \"SshSessionManager.open\", session_id: sessionId, profile: profile.name });\n _logger.info(\"ssh session opened\", { open_sessions: this.sessions.size });\n\n return session;\n }\n\n /**\n * Looks up a session, failing with the list of live ids so the caller can self-correct.\n *\n * @throws {Error} If no session matches `sessionId`.\n */\n require(sessionId: string): SshSession {\n const session = this.sessions.get(sessionId);\n if (session == null) {\n const openIds = Array.from(this.sessions.keys());\n\n let openSummary = \"none\";\n if (openIds.length > 0) {\n openSummary = openIds.join(\", \");\n }\n\n throw new Error(`unknown ssh session '${sessionId}' (open sessions: ${openSummary})`);\n }\n\n return session;\n }\n\n close(sessionId: string): boolean {\n const session = this.sessions.get(sessionId);\n if (session == null) {\n return false;\n }\n\n session.connection.disconnect();\n this.sessions.delete(sessionId);\n\n const _logger = $logger.child({ context: \"SshSessionManager.close\", session_id: sessionId });\n _logger.info(\"ssh session closed\", { open_sessions: this.sessions.size });\n\n return true;\n }\n\n closeAll(): void {\n for (const sessionId of Array.from(this.sessions.keys())) {\n this.close(sessionId);\n }\n }\n\n list(): SshSessionInfo[] {\n return Array.from(this.sessions.values()).map((session) => session.toInfo());\n }\n\n /** Starts the idle sweeper; the timer is unref'd so it never holds the process open. */\n startIdleSweeper(): void {\n if (this.sweepTimer != null) {\n return;\n }\n\n this.sweepTimer = setInterval(() => {\n const expiredAt = Date.now() - SESSION_IDLE_TIMEOUT_MS;\n for (const session of Array.from(this.sessions.values())) {\n // A long exec or a large transfer keeps a session busy well past the idle\n // window; reaping it there would abort the operation mid-flight.\n if (session.isBusy == true) {\n continue;\n }\n\n if (session.lastUsedAt.getTime() > expiredAt) {\n continue;\n }\n\n const _logger = $logger.child({\n context: \"SshSessionManager.sweep\",\n session_id: session.sessionId,\n idle_ms: Date.now() - session.lastUsedAt.getTime(),\n });\n _logger.info(\"closing idle ssh session\");\n this.close(session.sessionId);\n }\n }, SESSION_SWEEP_INTERVAL_MS);\n\n this.sweepTimer.unref();\n }\n\n stopIdleSweeper(): void {\n if (this.sweepTimer == null) {\n return;\n }\n\n clearInterval(this.sweepTimer);\n this.sweepTimer = null;\n }\n}\n","import fs from \"node:fs\";\nimport { StringDecoder } from \"node:string_decoder\";\n\nimport type { FileEntryWithStats, SFTPWrapper, Stats } from \"ssh2\";\n\nimport { MAX_DIRECTORY_ENTRIES } from \"@/_defs\";\nimport { $logger } from \"@/_libs\";\nimport type { SshRemoteEntry } from \"@/_types\";\nimport { GuardRejectionError, inspectRemotePath } from \"@/modules/guard\";\nimport type { RemotePathAccess } from \"@/modules/guard\";\n\nimport type { SshConnection } from \"./ssh-connection\";\n\n/**\n * Screens a remote path against the connection's own policy.\n *\n * Enforced here rather than in the tool handlers for the same reason `exec` screens its\n * own command: this is the layer every path must pass through, so a new tool cannot\n * forget the check.\n *\n * @throws {GuardRejectionError} If the policy refuses the path.\n */\nfunction requirePermittedPath(connection: SshConnection, remotePath: string, access: RemotePathAccess): void {\n const verdict = inspectRemotePath(remotePath, connection.profile.policy, access);\n if (verdict.allowed == false) {\n throw new GuardRejectionError(verdict);\n }\n}\n\nfunction toEntryType(attrs: Stats): SshRemoteEntry[\"type\"] {\n // SFTP attributes are flag-gated; without PERMISSIONS every predicate answers false.\n if (typeof attrs.mode !== \"number\") {\n return \"other\";\n }\n\n if (attrs.isDirectory() == true) {\n return \"directory\";\n }\n\n if (attrs.isSymbolicLink() == true) {\n return \"symlink\";\n }\n\n if (attrs.isFile() == true) {\n return \"file\";\n }\n\n return \"other\";\n}\n\n/**\n * ssh2 `Stats` → the listing shape returned to the model.\n *\n * Every field is optional on the wire: a server may answer readdir without SIZE or\n * ACMODTIME. Reading them unguarded turned one such entry into `new Date(NaN)` and a\n * thrown RangeError that failed the whole directory listing.\n */\nfunction toRemoteEntry(entry: FileEntryWithStats): SshRemoteEntry {\n const attrs = entry.attrs;\n\n let mode = \"?\";\n if (typeof attrs.mode === \"number\") {\n mode = `0${(attrs.mode & 0o7777).toString(8)}`;\n }\n\n let sizeBytes = 0;\n if (typeof attrs.size === \"number\" && Number.isFinite(attrs.size) == true) {\n sizeBytes = attrs.size;\n }\n\n let modifiedAt = \"unknown\";\n if (typeof attrs.mtime === \"number\" && Number.isFinite(attrs.mtime) == true) {\n modifiedAt = new Date(attrs.mtime * 1000).toISOString();\n }\n\n return {\n name: entry.filename,\n type: toEntryType(attrs),\n sizeBytes: sizeBytes,\n mode: mode,\n modifiedAt: modifiedAt,\n };\n}\n\nexport interface RemoteDirectoryListing {\n entries: SshRemoteEntry[];\n /** Entries the remote host reported, before the cap was applied. */\n totalCount: number;\n truncated: boolean;\n}\n\n/**\n * Lists a remote directory, directories first then files, each group alphabetical.\n *\n * Capped at `MAX_DIRECTORY_ENTRIES`: this is the one output path with no byte ceiling,\n * and a spool directory with half a million files would otherwise return megabytes.\n *\n * @throws {Error} If the path does not exist or is not readable.\n */\nexport async function listRemoteDirectory(\n connection: SshConnection,\n remotePath: string\n): Promise<RemoteDirectoryListing> {\n requirePermittedPath(connection, remotePath, \"read\");\n\n return await connection.withSftp(async (sftp: SFTPWrapper) => {\n const entries = await new Promise<FileEntryWithStats[]>((resolve, reject) => {\n sftp.readdir(remotePath, (error, list) => {\n if (error != null) {\n reject(error);\n return;\n }\n\n resolve(list);\n });\n });\n\n const mapped = entries.map(toRemoteEntry);\n mapped.sort((left, right) => {\n if (left.type === \"directory\" && right.type !== \"directory\") {\n return -1;\n }\n\n if (left.type !== \"directory\" && right.type === \"directory\") {\n return 1;\n }\n\n return left.name.localeCompare(right.name);\n });\n\n return {\n entries: mapped.slice(0, MAX_DIRECTORY_ENTRIES),\n totalCount: mapped.length,\n truncated: mapped.length > MAX_DIRECTORY_ENTRIES,\n };\n });\n}\n\nexport interface RemoteFileContent {\n content: string;\n /** Size the remote host reported; 0 for virtual files that do not declare one. */\n sizeBytes: number;\n /** Bytes actually read. */\n readBytes: number;\n truncated: boolean;\n}\n\n/**\n * Reads a remote file as UTF-8, stopping after `maxBytes`.\n *\n * Oversized files return their leading bytes rather than an error — a 2 GB log is exactly\n * the case where the first chunk is what you wanted anyway.\n *\n * A reported size of 0 does not mean empty: every file under /proc and most of /sys says 0\n * while holding real content. Those are read unbounded up to `maxBytes` instead of being\n * range-limited, which previously returned exactly one byte and called it the whole file.\n *\n * @throws {Error} If the path is missing, is a directory, or is not readable.\n */\nexport async function readRemoteFile(\n connection: SshConnection,\n remotePath: string,\n maxBytes: number\n): Promise<RemoteFileContent> {\n requirePermittedPath(connection, remotePath, \"read\");\n\n return await connection.withSftp(async (sftp: SFTPWrapper) => {\n const attrs = await new Promise<Stats>((resolve, reject) => {\n sftp.stat(remotePath, (error, stats) => {\n if (error != null) {\n reject(error);\n return;\n }\n\n resolve(stats);\n });\n });\n\n if (attrs.isDirectory() == true) {\n throw new Error(`${remotePath} is a directory, use ssh_list_dir instead`);\n }\n\n let declaredSize = 0;\n if (typeof attrs.size === \"number\" && Number.isFinite(attrs.size) == true) {\n declaredSize = attrs.size;\n }\n\n const isSizeKnown = declaredSize > 0;\n\n const streamOptions: { start?: number; end?: number } = {};\n if (isSizeKnown == true) {\n streamOptions.start = 0;\n streamOptions.end = Math.min(declaredSize, maxBytes) - 1;\n }\n\n const chunks: Buffer[] = [];\n let collectedBytes = 0;\n\n await new Promise<void>((resolve, reject) => {\n const stream = sftp.createReadStream(remotePath, streamOptions);\n\n stream.on(\"data\", (chunk: Buffer) => {\n chunks.push(chunk);\n collectedBytes += chunk.length;\n\n if (collectedBytes >= maxBytes) {\n stream.destroy();\n resolve();\n }\n });\n stream.on(\"error\", (error: Error) => {\n reject(error);\n });\n stream.on(\"end\", () => {\n resolve();\n });\n stream.on(\"close\", () => {\n resolve();\n });\n });\n\n const buffer = Buffer.concat(chunks, Math.min(collectedBytes, maxBytes));\n\n let truncated = false;\n if (isSizeKnown == true) {\n truncated = declaredSize > buffer.length;\n }\n else {\n truncated = buffer.length >= maxBytes;\n }\n\n // Decoded through StringDecoder for the same reason the exec path does: the cut\n // lands at an arbitrary byte offset, and a plain toString() turns the multi-byte\n // character straddling it into U+FFFD. `end()` drops the incomplete tail instead.\n const decoder = new StringDecoder(\"utf8\");\n const content = decoder.write(buffer) + decoder.end();\n\n return {\n content: content,\n sizeBytes: declaredSize,\n readBytes: buffer.length,\n truncated: truncated,\n };\n });\n}\n\n/**\n * Writes UTF-8 text to a remote path, replacing or appending.\n *\n * @throws {Error} If the parent directory is missing or the account cannot write there.\n */\nexport async function writeRemoteFile(\n connection: SshConnection,\n args: { remotePath: string; content: string; append: boolean }\n): Promise<number> {\n const { remotePath, content, append } = args;\n\n requirePermittedPath(connection, remotePath, \"write\");\n\n const payload = Buffer.from(content, \"utf8\");\n\n await connection.withSftp(async (sftp: SFTPWrapper) => {\n await new Promise<void>((resolve, reject) => {\n const callback = (error: Error | null | undefined): void => {\n if (error != null) {\n reject(error);\n return;\n }\n\n resolve();\n };\n\n if (append == true) {\n sftp.appendFile(remotePath, payload, callback);\n return;\n }\n\n sftp.writeFile(remotePath, payload, callback);\n });\n });\n\n const _logger = $logger.child({\n context: \"writeRemoteFile\",\n profile: connection.profile.name,\n remote_path: remotePath,\n append: append,\n });\n _logger.info(\"remote file written\", { bytes: payload.length });\n\n return payload.length;\n}\n\n/**\n * Uploads a local file with SFTP.\n *\n * @returns Bytes transferred.\n * @throws {Error} If the local file is missing or the remote path is not writable.\n */\nexport async function uploadFile(\n connection: SshConnection,\n localPath: string,\n remotePath: string\n): Promise<number> {\n requirePermittedPath(connection, remotePath, \"write\");\n\n const localStats = fs.statSync(localPath);\n if (localStats.isFile() == false) {\n throw new Error(`local path is not a file: ${localPath}`);\n }\n\n await connection.withSftp(async (sftp: SFTPWrapper) => {\n await new Promise<void>((resolve, reject) => {\n sftp.fastPut(localPath, remotePath, (error) => {\n if (error != null) {\n reject(error);\n return;\n }\n\n resolve();\n });\n });\n });\n\n const _logger = $logger.child({\n context: \"uploadFile\",\n profile: connection.profile.name,\n local_path: localPath,\n remote_path: remotePath,\n });\n _logger.info(\"file uploaded\", { bytes: localStats.size });\n\n return localStats.size;\n}\n\n/**\n * Downloads a remote file with SFTP.\n *\n * @returns Bytes written locally.\n * @throws {Error} If the remote file is missing or the local path is not writable.\n */\nexport async function downloadFile(\n connection: SshConnection,\n remotePath: string,\n localPath: string\n): Promise<number> {\n requirePermittedPath(connection, remotePath, \"read\");\n\n await connection.withSftp(async (sftp: SFTPWrapper) => {\n await new Promise<void>((resolve, reject) => {\n sftp.fastGet(remotePath, localPath, (error) => {\n if (error != null) {\n reject(error);\n return;\n }\n\n resolve();\n });\n });\n });\n\n const localStats = fs.statSync(localPath);\n\n const _logger = $logger.child({\n context: \"downloadFile\",\n profile: connection.profile.name,\n remote_path: remotePath,\n local_path: localPath,\n });\n _logger.info(\"file downloaded\", { bytes: localStats.size });\n\n return localStats.size;\n}\n","import { z } from \"zod\";\n\n/**\n * Policy knobs, all optional — unset fields fall back to `defaults`, then to the built-ins.\n *\n * Strict on purpose. A permissive object *strips* unknown keys, so `readOnly: true`\n * (capital O) parsed successfully and silently vanished, leaving a host the operator\n * believed was read-only fully writable. An unknown key must fail startup instead.\n */\nexport const POLICY_INPUT_SCHEMA = z.strictObject({\n readonly: z.boolean().optional(),\n allowSudo: z.boolean().optional(),\n execTimeoutMs: z.number().int().positive().optional(),\n connectTimeoutMs: z.number().int().positive().optional(),\n maxOutputCharacters: z.number().int().positive().optional(),\n maxReadFileBytes: z.number().int().positive().optional(),\n allowCommands: z.array(z.string()).optional(),\n denyPatterns: z.array(z.string()).optional(),\n allowedPaths: z.array(z.string()).optional(),\n});\n\n/** One `hosts` entry: connection fields plus the same policy knobs as an override. */\nexport const HOST_INPUT_SCHEMA = POLICY_INPUT_SCHEMA.extend({\n // Kept strict by `.extend()` on a strict base — verified by the config tests.\n host: z.string().min(1),\n port: z.number().int().min(1).max(65535).optional(),\n username: z.string().min(1),\n description: z.string().optional(),\n privateKeyPath: z.string().optional(),\n privateKey: z.string().optional(),\n passphrase: z.string().optional(),\n /** Name of an env var holding the passphrase, preferred over inlining it. */\n passphraseEnv: z.string().optional(),\n password: z.string().optional(),\n /** Name of an env var holding the password, preferred over inlining it. */\n passwordEnv: z.string().optional(),\n /** Pinned server host key, e.g. \"SHA256:abc123…\". */\n hostKeyFingerprint: z.string().optional(),\n defaultCwd: z.string().optional(),\n});\n\nexport const CONFIG_INPUT_SCHEMA = z.strictObject({\n /** Ignored at runtime; present so editors can attach a JSON schema. */\n $schema: z.string().optional(),\n defaults: POLICY_INPUT_SCHEMA.optional(),\n hosts: z.record(z.string(), HOST_INPUT_SCHEMA),\n});\n\nexport type PolicyInput = z.infer<typeof POLICY_INPUT_SCHEMA>;\nexport type HostInput = z.infer<typeof HOST_INPUT_SCHEMA>;\nexport type ConfigInput = z.infer<typeof CONFIG_INPUT_SCHEMA>;\n","import { FALSY_ENV_VALUES, SINGLE_HOST_ENV, TRUTHY_ENV_VALUES } from \"@/_defs\";\nimport { $logger } from \"@/_libs\";\n\nimport type { ConfigInput, HostInput } from \"./config-schema\";\n\n/** Trimmed value, or undefined when the variable is unset or blank. */\nfunction readEnv(name: string): string | undefined {\n const value = process.env[name];\n if (value == null) {\n return undefined;\n }\n\n const trimmed = value.trim();\n if (trimmed === \"\") {\n return undefined;\n }\n\n return trimmed;\n}\n\n/**\n * @throws {Error} If the value is set but is neither a truthy nor a falsy spelling —\n * `SSH_READONLY=ture` must fail loudly, not resolve to \"not read-only\".\n */\nfunction readBooleanEnv(name: string): boolean | undefined {\n const value = readEnv(name);\n if (value == null) {\n return undefined;\n }\n\n const normalized = value.toLowerCase();\n if (TRUTHY_ENV_VALUES.includes(normalized) == true) {\n return true;\n }\n\n if (FALSY_ENV_VALUES.includes(normalized) == false) {\n throw new Error(`${name} must be one of ${[...TRUTHY_ENV_VALUES, ...FALSY_ENV_VALUES].join(\", \")} (got \"${value}\")`);\n }\n\n return false;\n}\n\n/**\n * @throws {Error} If the value is set but is not a positive integer.\n */\nfunction readIntegerEnv(name: string): number | undefined {\n const value = readEnv(name);\n if (value == null) {\n return undefined;\n }\n\n const parsed = Number(value);\n if (Number.isInteger(parsed) == false || parsed <= 0) {\n throw new Error(`${name} must be a positive integer (got \"${value}\")`);\n }\n\n return parsed;\n}\n\n/** Comma-separated list, blanks dropped. */\nfunction readListEnv(name: string): string[] | undefined {\n const value = readEnv(name);\n if (value == null) {\n return undefined;\n }\n\n const items = value.split(\",\").map((item) => item.trim()).filter((item) => item !== \"\");\n if (items.length === 0) {\n return undefined;\n }\n\n return items;\n}\n\n/**\n * Builds a one-host config from the `SSH_*` variables, or null when `SSH_HOST` is unset.\n *\n * The intended shape is one MCP server entry per host, so the profile alias defaults to\n * the hostname and the model rarely needs to name it at all.\n *\n * @throws {Error} If `SSH_HOST` is set without `SSH_USER`, or a typed value is malformed.\n */\nexport function buildConfigFromEnv(): ConfigInput | null {\n const host = readEnv(SINGLE_HOST_ENV.HOST);\n if (host == null) {\n return null;\n }\n\n const username = readEnv(SINGLE_HOST_ENV.USER);\n if (username == null) {\n throw new Error(`${SINGLE_HOST_ENV.HOST} is set, so ${SINGLE_HOST_ENV.USER} is required`);\n }\n\n const hostInput: HostInput = {\n host: host,\n username: username,\n port: readIntegerEnv(SINGLE_HOST_ENV.PORT),\n description: readEnv(SINGLE_HOST_ENV.DESCRIPTION),\n privateKeyPath: readEnv(SINGLE_HOST_ENV.KEY),\n passphrase: readEnv(SINGLE_HOST_ENV.PASSPHRASE),\n password: readEnv(SINGLE_HOST_ENV.PASSWORD),\n hostKeyFingerprint: readEnv(SINGLE_HOST_ENV.HOST_KEY),\n defaultCwd: readEnv(SINGLE_HOST_ENV.CWD),\n readonly: readBooleanEnv(SINGLE_HOST_ENV.READONLY),\n allowSudo: readBooleanEnv(SINGLE_HOST_ENV.ALLOW_SUDO),\n allowCommands: readListEnv(SINGLE_HOST_ENV.ALLOW_COMMANDS),\n denyPatterns: readListEnv(SINGLE_HOST_ENV.DENY_PATTERNS),\n allowedPaths: readListEnv(SINGLE_HOST_ENV.ALLOWED_PATHS),\n execTimeoutMs: readIntegerEnv(SINGLE_HOST_ENV.EXEC_TIMEOUT_MS),\n connectTimeoutMs: readIntegerEnv(SINGLE_HOST_ENV.CONNECT_TIMEOUT_MS),\n maxOutputCharacters: readIntegerEnv(SINGLE_HOST_ENV.MAX_OUTPUT_CHARACTERS),\n maxReadFileBytes: readIntegerEnv(SINGLE_HOST_ENV.MAX_READ_FILE_BYTES),\n };\n\n const name = readEnv(SINGLE_HOST_ENV.NAME) ?? host;\n\n const _logger = $logger.child({ context: \"buildConfigFromEnv\", profile: name });\n _logger.debug(\"single-host config assembled from environment variables\");\n\n return { hosts: { [name]: hostInput } };\n}\n","import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nimport {\n CONFIG_PATH_ENV,\n SINGLE_HOST_ENV,\n DEFAULT_CONFIG_FILENAMES,\n DEFAULT_SSH_PORT,\n DEFAULT_EXEC_TIMEOUT_MS,\n DEFAULT_CONNECT_TIMEOUT_MS,\n DEFAULT_MAX_OUTPUT_CHARACTERS,\n DEFAULT_MAX_READ_FILE_BYTES,\n} from \"@/_defs\";\nimport { $logger, expandHomePath } from \"@/_libs\";\nimport type { SshHostProfile, SshHostSummary, SshMcpConfig, SshPolicy } from \"@/_types\";\n\nimport { CONFIG_INPUT_SCHEMA } from \"./config-schema\";\nimport type { ConfigInput, HostInput, PolicyInput } from \"./config-schema\";\nimport { buildConfigFromEnv } from \"./env-host\";\n\n/** Where the profile definitions come from. */\ntype ConfigSource =\n | { kind: \"env\"; config: ConfigInput }\n | { kind: \"inline\"; json: string }\n | { kind: \"file\"; path: string }\n | { kind: \"none\" };\n\n/**\n * Resolves the config source.\n *\n * Order, most specific first:\n *\n * 1. `--config <path>` — an explicit path always wins.\n * 2. `SSH_HOST` — **one host from plain `SSH_*` variables**. The intended shape: one MCP\n * server entry per host, each configured like a connection form. No JSON inside JSON.\n * 3. `SSH_MCP_CONFIG` — several hosts at once, as JSON (value starts with `{`) or a path\n * to a JSON file. A JSON object always starts with `{` and a path never does.\n * 4. The home-directory config files.\n *\n * @throws {Error} If `SSH_HOST` is set but its companion variables are malformed.\n */\nfunction resolveConfigSource(explicitPath?: string): ConfigSource {\n if (explicitPath != null && explicitPath.trim() !== \"\") {\n return { kind: \"file\", path: expandHomePath(explicitPath) };\n }\n\n const fromSingleHostEnv = buildConfigFromEnv();\n if (fromSingleHostEnv != null) {\n return { kind: \"env\", config: fromSingleHostEnv };\n }\n\n const fromEnv = process.env[CONFIG_PATH_ENV];\n if (fromEnv != null && fromEnv.trim() !== \"\") {\n const trimmedValue = fromEnv.trim();\n if (trimmedValue.startsWith(\"{\") == true) {\n return { kind: \"inline\", json: trimmedValue };\n }\n\n return { kind: \"file\", path: expandHomePath(trimmedValue) };\n }\n\n for (const filename of DEFAULT_CONFIG_FILENAMES) {\n const candidate = path.join(os.homedir(), filename);\n if (fs.existsSync(candidate) == true) {\n return { kind: \"file\", path: candidate };\n }\n }\n\n return { kind: \"none\" };\n}\n\n/**\n * Compiles `denyPatterns` at load time.\n *\n * Lazily compiling them at first use meant a typo'd regex logged one stderr line and then\n * simply wasn't in force — the operator's own deny rule, silently absent, on a server that\n * reported \"config loaded\". Every other malformed field aborts startup; so does this now.\n *\n * @throws {Error} If a pattern is not a valid regular expression.\n */\nfunction compileDenyPatterns(profileName: string, sources: string[]): RegExp[] {\n return sources.map((source) => {\n try {\n return new RegExp(source, \"i\");\n }\n catch (ex) {\n const _logger = $logger.child({ context: \"compileDenyPatterns\", profile: profileName });\n _logger.error(ex, \"denyPatterns entry is not a valid regular expression\");\n\n let detail = String(ex);\n if (ex instanceof Error) {\n detail = ex.message;\n }\n\n throw new Error(`profile '${profileName}' has an invalid denyPatterns entry /${source}/: ${detail}`);\n }\n });\n}\n\n/**\n * Built-in defaults ← config `defaults` ← per-host override, applied in that order.\n *\n * The built-in stance is permissive: an unconfigured host allows everything except the\n * catastrophe rules. Restriction is opt-in, because a guard nobody can work through gets\n * turned off wholesale rather than tuned.\n *\n * An explicitly empty array on a host *overrides* a restrictive `defaults` block — it is\n * read as \"no restriction here\", which is what the syntax says. It is warned about,\n * because \"nothing extra\" is the other reading and the two are opposite.\n */\nfunction resolvePolicy(profileName: string, defaults: PolicyInput | undefined, override: PolicyInput): SshPolicy {\n const allowCommands = [...(override.allowCommands ?? defaults?.allowCommands ?? [])];\n\n // `ssh_connect` probes with `pwd` to settle the session's starting directory; without\n // this an allow-list profile could never open a session at all.\n if (allowCommands.length > 0 && allowCommands.includes(\"pwd\") == false) {\n allowCommands.push(\"pwd\");\n }\n\n const denyPatternSources = override.denyPatterns ?? defaults?.denyPatterns ?? [];\n const allowedPaths = override.allowedPaths ?? defaults?.allowedPaths ?? [];\n\n const _logger = $logger.child({ context: \"resolvePolicy\", profile: profileName });\n if (override.allowCommands?.length === 0 && (defaults?.allowCommands?.length ?? 0) > 0) {\n _logger.warn(\"host sets allowCommands to an empty list, which removes the restriction from defaults\");\n }\n if (override.allowedPaths?.length === 0 && (defaults?.allowedPaths?.length ?? 0) > 0) {\n _logger.warn(\"host sets allowedPaths to an empty list, which removes the restriction from defaults\");\n }\n\n return {\n readonly: override.readonly ?? defaults?.readonly ?? false,\n allowSudo: override.allowSudo ?? defaults?.allowSudo ?? true,\n execTimeoutMs: override.execTimeoutMs ?? defaults?.execTimeoutMs ?? DEFAULT_EXEC_TIMEOUT_MS,\n connectTimeoutMs: override.connectTimeoutMs ?? defaults?.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,\n maxOutputCharacters: override.maxOutputCharacters ?? defaults?.maxOutputCharacters ?? DEFAULT_MAX_OUTPUT_CHARACTERS,\n maxReadFileBytes: override.maxReadFileBytes ?? defaults?.maxReadFileBytes ?? DEFAULT_MAX_READ_FILE_BYTES,\n allowCommands: allowCommands,\n denyPatterns: compileDenyPatterns(profileName, denyPatternSources),\n allowedPaths: allowedPaths,\n };\n}\n\n/** Reads a secret straight from the config, or from the env var named by `*Env`. */\nfunction resolveSecret(\n profileName: string,\n inlineValue: string | undefined,\n envVarName: string | undefined\n): string | undefined {\n if (envVarName == null) {\n return inlineValue;\n }\n\n const fromEnv = process.env[envVarName];\n if (fromEnv == null || fromEnv === \"\") {\n const _logger = $logger.child({ context: \"resolveSecret\", profile: profileName, env_var: envVarName });\n _logger.warn(\"env var referenced by the profile is empty; falling back to the inline value\");\n return inlineValue;\n }\n\n return fromEnv;\n}\n\n/** Config entry (wire shape) → the profile the rest of the server works with. */\nfunction toHostProfile(name: string, raw: HostInput, defaults: PolicyInput | undefined): SshHostProfile {\n const profile: SshHostProfile = {\n name: name,\n host: raw.host,\n port: raw.port ?? DEFAULT_SSH_PORT,\n username: raw.username,\n description: raw.description,\n privateKey: raw.privateKey,\n passphrase: resolveSecret(name, raw.passphrase, raw.passphraseEnv),\n password: resolveSecret(name, raw.password, raw.passwordEnv),\n hostKeyFingerprint: raw.hostKeyFingerprint,\n defaultCwd: raw.defaultCwd,\n policy: resolvePolicy(name, defaults, raw),\n };\n\n if (raw.privateKeyPath != null) {\n const expandedKeyPath = expandHomePath(raw.privateKeyPath);\n profile.privateKeyPath = expandedKeyPath;\n\n // Checked at load, not at first use: a typo'd key path would otherwise surface as\n // a connection failure minutes later, with the path withheld from the message.\n if (fs.existsSync(expandedKeyPath) == false) {\n const _logger = $logger.child({ context: \"toHostProfile\", profile: name });\n _logger.warn(\"privateKeyPath does not exist; connections for this profile will fail\", {\n private_key_path: expandedKeyPath,\n });\n }\n }\n\n return profile;\n}\n\n/** Warns when the config is group/world readable — it holds passwords and key paths. */\nfunction warnOnLoosePermissions(configPath: string): void {\n if (process.platform === \"win32\") {\n return;\n }\n\n const stats = fs.statSync(configPath);\n const permissionBits = stats.mode & 0o777;\n if ((permissionBits & 0o077) === 0) {\n return;\n }\n\n const _logger = $logger.child({ context: \"warnOnLoosePermissions\", config_path: configPath });\n _logger.warn(`config file is readable by other users, run: chmod 600 ${configPath}`, {\n mode: permissionBits.toString(8),\n });\n}\n\n/**\n * Loads host profiles from disk.\n *\n * A missing config is not an error — the server still starts and reports \"no profiles\"\n * through the tools, which is a far clearer signal to the model than a dead server.\n * A config that exists but is malformed *is* an error: silently ignoring it would let a\n * typo in a policy field quietly drop a `readonly` guard.\n *\n * @throws {Error} If the resolved path is missing, unreadable, not JSON, or fails validation.\n */\nexport function loadConfig(explicitPath?: string): SshMcpConfig {\n let _logger = $logger.child({ context: \"loadConfig\" });\n\n const source = resolveConfigSource(explicitPath);\n if (source.kind === \"none\") {\n _logger.warn(\"no config found; no host profiles are registered\", {\n searched: DEFAULT_CONFIG_FILENAMES,\n env_vars: [SINGLE_HOST_ENV.HOST, CONFIG_PATH_ENV],\n });\n return { profiles: new Map(), sourcePath: null, sourceLabel: \"none\" };\n }\n\n let parsedJson: unknown = null;\n let sourcePath: string | null = null;\n let sourceLabel = `inline ${CONFIG_PATH_ENV}`;\n\n if (source.kind === \"env\") {\n _logger = _logger.child({ config_source: \"env\" });\n sourceLabel = `${SINGLE_HOST_ENV.HOST} environment variables`;\n parsedJson = source.config;\n }\n else {\n let rawText = \"\";\n\n if (source.kind === \"inline\") {\n _logger = _logger.child({ config_source: \"inline\" });\n rawText = source.json;\n }\n else {\n _logger = _logger.child({ config_path: source.path });\n sourcePath = source.path;\n sourceLabel = source.path;\n\n if (fs.existsSync(source.path) == false) {\n _logger.error(null, \"config file does not exist\");\n throw new Error(`ssh mcp config not found: ${source.path}`);\n }\n\n rawText = fs.readFileSync(source.path, \"utf8\");\n }\n\n try {\n parsedJson = JSON.parse(rawText);\n }\n catch (ex) {\n _logger.error(ex, \"config is not valid json\");\n throw new Error(`ssh mcp config is not valid JSON (${sourceLabel})`);\n }\n }\n\n const validated = CONFIG_INPUT_SCHEMA.safeParse(parsedJson);\n if (validated.success == false) {\n const issueSummary = validated.error.issues\n .map((issue) => `${issue.path.join(\".\")}: ${issue.message}`)\n .join(\"; \");\n _logger.error(validated.error, \"config failed schema validation\");\n throw new Error(`ssh mcp config is invalid (${sourceLabel}): ${issueSummary}`);\n }\n\n if (sourcePath != null) {\n warnOnLoosePermissions(sourcePath);\n }\n\n const profiles = new Map<string, SshHostProfile>();\n for (const [name, hostInput] of Object.entries(validated.data.hosts)) {\n profiles.set(name, toHostProfile(name, hostInput, validated.data.defaults));\n }\n\n _logger.info(\"config loaded\", {\n profile_count: profiles.size,\n profiles: Array.from(profiles.keys()),\n });\n\n return { profiles: profiles, sourcePath: sourcePath, sourceLabel: sourceLabel };\n}\n\n/** Strips every secret so a profile can be described back to the model. */\nexport function toHostSummary(profile: SshHostProfile): SshHostSummary {\n let authMethod: SshHostSummary[\"authMethod\"] = \"agent\";\n if (profile.privateKeyPath != null || profile.privateKey != null) {\n authMethod = \"privateKey\";\n }\n else if (profile.password != null) {\n authMethod = \"password\";\n }\n\n return {\n name: profile.name,\n host: profile.host,\n port: profile.port,\n username: profile.username,\n description: profile.description,\n authMethod: authMethod,\n readonly: profile.policy.readonly,\n allowSudo: profile.policy.allowSudo,\n allowedPaths: profile.policy.allowedPaths,\n allowCommands: profile.policy.allowCommands,\n };\n}\n","import { CONFIG_PATH_ENV, DEFAULT_CONFIG_FILENAMES } from \"@/_defs\";\nimport { formatBytes } from \"@/_libs\";\nimport type {\n GuardVerdict,\n SshExecResult,\n SshMcpConfig,\n SshRemoteEntry,\n SshSessionInfo,\n} from \"@/_types\";\nimport { toHostSummary } from \"@/modules/config\";\nimport type { RemoteDirectoryListing } from \"@/modules/ssh\";\n\nconst ENTRY_TYPE_MARKERS: Record<SshRemoteEntry[\"type\"], string> = {\n file: \"-\",\n directory: \"d\",\n symlink: \"l\",\n other: \"?\",\n};\n\n/**\n * Renders the registered profiles for `ssh_list_hosts`, or setup instructions when none\n * are configured. Credential fields never appear — only which auth method is in use.\n */\nexport function formatHostList(config: SshMcpConfig): string {\n if (config.profiles.size === 0) {\n return [\n \"No SSH host profiles are registered.\",\n \"\",\n `Put them in this server's MCP entry — ${CONFIG_PATH_ENV} takes the JSON itself:`,\n \"\",\n ` \"env\": {`,\n ` \"${CONFIG_PATH_ENV}\": \"{\\\\\"hosts\\\\\":{\\\\\"my-server\\\\\":{\\\\\"host\\\\\":\\\\\"10.0.0.5\\\\\",\\\\\"username\\\\\":\\\\\"deploy\\\\\",\\\\\"privateKeyPath\\\\\":\\\\\"~/.ssh/id_ed25519\\\\\"}}}\"`,\n \" }\",\n \"\",\n `It also accepts a path to a JSON file, and ~/${DEFAULT_CONFIG_FILENAMES[0]} is picked up automatically.`,\n \"Restart this server after changing it.\",\n ].join(\"\\n\");\n }\n\n const lines: string[] = [];\n lines.push(`${config.profiles.size} SSH host profile(s) from ${config.sourceLabel}:`);\n\n for (const profile of config.profiles.values()) {\n const summary = toHostSummary(profile);\n\n let accessLabel = \"writable\";\n if (summary.readonly == true) {\n accessLabel = \"READ-ONLY\";\n }\n\n let sudoLabel = \"sudo=disabled\";\n if (summary.allowSudo == true) {\n sudoLabel = \"sudo=enabled\";\n }\n\n lines.push(\"\");\n lines.push(`${summary.name} → ${summary.username}@${summary.host}:${summary.port} auth=${summary.authMethod} ${accessLabel} ${sudoLabel}`);\n\n if (summary.description != null) {\n lines.push(` ${summary.description}`);\n }\n\n if (summary.allowedPaths.length > 0) {\n // Scope stated explicitly: allowedPaths binds the SFTP tools only, and reading\n // it as a filesystem-wide restriction would be a dangerous misunderstanding —\n // ssh_exec can still `cat` anything the remote account can read.\n lines.push(` file tools limited to: ${summary.allowedPaths.join(\", \")} (does not restrict ssh_exec)`);\n }\n\n if (summary.allowCommands.length > 0) {\n lines.push(` commands limited to: ${summary.allowCommands.join(\", \")}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Renders a command result: a status line (exit code, duration, cwd), any timeout or\n * truncation notice, then the stdout and stderr sections.\n *\n * @param timeoutMs The limit that applied, quoted in the timeout notice.\n */\nexport function formatExecResult(result: SshExecResult, timeoutMs: number): string {\n const headerParts: string[] = [];\n\n if (result.exitCode != null) {\n headerParts.push(`exit code: ${result.exitCode}`);\n }\n else {\n headerParts.push(\"exit code: none (killed)\");\n }\n\n if (result.signal != null) {\n headerParts.push(`signal: ${result.signal}`);\n }\n\n headerParts.push(`${result.durationMs}ms`);\n\n if (result.cwd != null) {\n headerParts.push(`cwd: ${result.cwd}`);\n }\n\n const lines: string[] = [headerParts.join(\" · \")];\n\n if (result.timedOut == true) {\n lines.push(`TIMED OUT after ${timeoutMs}ms — the channel was closed, but the remote process may still be running.`);\n }\n\n if (result.truncated == true) {\n lines.push(\"Output was truncated; narrow the command (grep / head / tail) or raise maxOutputCharacters for this profile.\");\n }\n\n lines.push(\"\");\n lines.push(\"--- stdout ---\");\n if (result.stdout === \"\") {\n lines.push(\"(empty)\");\n }\n else {\n lines.push(result.stdout);\n }\n\n if (result.stderr !== \"\") {\n lines.push(\"\");\n lines.push(\"--- stderr ---\");\n lines.push(result.stderr);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Rejection message: what was blocked, why, and what would make it legal. */\nexport function formatGuardRejection(action: string, verdict: GuardVerdict): string {\n const lines: string[] = [`Blocked by the host profile's guard policy: ${verdict.reason}`];\n\n if (verdict.offendingText != null && verdict.offendingText !== action) {\n lines.push(`Offending part: ${verdict.offendingText}`);\n }\n\n lines.push(`Requested: ${action}`);\n lines.push(\"Nothing was sent to the remote host. Adjust the request, or relax the profile's policy in the config file.\");\n\n return lines.join(\"\\n\");\n}\n\n/** Renders open sessions with host, working directory, command count and idle time. */\nexport function formatSessionList(sessions: SshSessionInfo[]): string {\n if (sessions.length === 0) {\n return \"No open SSH sessions. Open one with ssh_connect, or pass 'target' to run a one-off command.\";\n }\n\n const lines: string[] = [`${sessions.length} open SSH session(s):`];\n const now = Date.now();\n\n for (const session of sessions) {\n const idleSeconds = Math.round((now - new Date(session.lastUsedAt).getTime()) / 1000);\n lines.push(\"\");\n lines.push(`${session.sessionId} → ${session.username}@${session.host} profile: ${session.profileName}`);\n lines.push(` cwd: ${session.cwd} · ${session.execCount} command(s) · idle ${idleSeconds}s · opened ${session.openedAt}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Renders a directory listing as one row per entry (type, mode, size, mtime, name),\n * noting the true total when the listing was capped.\n */\nexport function formatDirectoryListing(remotePath: string, listing: RemoteDirectoryListing): string {\n if (listing.totalCount === 0) {\n return `${remotePath} is empty.`;\n }\n\n let header = `${remotePath} — ${listing.totalCount} entrie(s):`;\n if (listing.truncated == true) {\n header = `${remotePath} — ${listing.totalCount} entrie(s), showing the first ${listing.entries.length}:`;\n }\n\n const lines: string[] = [header, \"\"];\n\n for (const entry of listing.entries) {\n const marker = ENTRY_TYPE_MARKERS[entry.type];\n const size = formatBytes(entry.sizeBytes).padStart(9);\n\n let name = entry.name;\n if (entry.type === \"directory\") {\n name = `${entry.name}/`;\n }\n\n lines.push(`${marker} ${entry.mode} ${size} ${entry.modifiedAt} ${name}`);\n }\n\n if (listing.truncated == true) {\n lines.push(\"\");\n lines.push(\"Listing was capped; narrow the path or filter with ssh_exec if you need the rest.\");\n }\n\n return lines.join(\"\\n\");\n}\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { CONFIG_PATH_ENV, SINGLE_HOST_ENV } from \"@/_defs\";\nimport { $logger } from \"@/_libs\";\nimport type { SshHostProfile, SshMcpConfig } from \"@/_types\";\nimport { GuardRejectionError } from \"@/modules/guard\";\nimport { SshConnection, SshSession, SshSessionManager } from \"@/modules/ssh\";\n\nimport { formatGuardRejection } from \"./format\";\n\n/**\n * Ceiling on simultaneous one-off connections, which the session manager never sees.\n * Matched to the session cap: an MCP client can dispatch a whole tool batch at once, and\n * a limit low enough to reject an ordinary batch is worse than the fan-out it prevents.\n */\nconst MAX_EPHEMERAL_CONNECTIONS = 32;\n\nlet activeEphemeralCount = 0;\n\n/** Everything the tool handlers share: the loaded profiles and the live sessions. */\nexport interface ToolContext {\n config: SshMcpConfig;\n sessions: SshSessionManager;\n /**\n * Re-reads the config source and swaps it in, so `context.config` is always current.\n * Implemented by the server, which owns the source path.\n */\n reloadConfig(): SshMcpConfig;\n}\n\nexport function textResult(text: string): CallToolResult {\n return { content: [{ type: \"text\", text: text }] };\n}\n\n/** Marked `isError` so the model sees the call failed rather than reading it as output. */\nexport function errorResult(message: string): CallToolResult {\n return { content: [{ type: \"text\", text: message }], isError: true };\n}\n\nexport function describeError(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\n/**\n * Renders a failure for the model, separating the two cases it must treat differently:\n * a guard rejection is a policy decision not worth retrying, anything else is an\n * operational failure that might succeed on a second attempt.\n */\nexport function toToolError(error: unknown, toolName: string, action: string): CallToolResult {\n const _logger = $logger.child({ context: toolName });\n\n if (error instanceof GuardRejectionError) {\n _logger.warn(\"rejected by the guard\", { reason: error.verdict.reason, action: action });\n\n const rendered = formatGuardRejection(action, error.verdict);\n return errorResult(rendered);\n }\n\n _logger.error(error, `${toolName} failed`);\n return errorResult(`${toolName} failed: ${describeError(error)}`);\n}\n\n/**\n * Looks up a profile by alias.\n *\n * @throws {Error} If the alias is unknown, listing what is available so the model can retry.\n */\nexport function requireProfile(context: ToolContext, target: string): SshHostProfile {\n const profile = context.config.profiles.get(target);\n if (profile != null) {\n return profile;\n }\n\n const available = Array.from(context.config.profiles.keys());\n if (available.length === 0) {\n throw new Error(`no host profiles are registered — set ${SINGLE_HOST_ENV.HOST} / ${SINGLE_HOST_ENV.USER} in this server's env block (or ${CONFIG_PATH_ENV} for several hosts), then restart it`);\n }\n\n throw new Error(`unknown host profile '${target}' (registered: ${available.join(\", \")})`);\n}\n\n/**\n * Resolves the `target` / `session` argument pair to a profile, without connecting.\n *\n * `target` is **optional when the server fronts a single host** — the intended shape is\n * one MCP server entry per host, where naming it every call is noise. With several hosts\n * registered it becomes required, and the error lists them.\n *\n * Supplying both `target` and `session` is rejected rather than resolved: they can name\n * different hosts under different policies, so the request is ambiguous.\n *\n * @throws {Error} If both are supplied, if `target` is omitted with several hosts\n * registered, or if the value supplied does not resolve.\n */\nexport function resolveProfile(\n context: ToolContext,\n args: { target?: string; session?: string }\n): { profile: SshHostProfile; session: SshSession | null } {\n const hasTarget = args.target != null && args.target.trim() !== \"\";\n const hasSession = args.session != null && args.session.trim() !== \"\";\n\n if (hasTarget == true && hasSession == true) {\n throw new Error(\"pass either 'target' or 'session', not both — they can name different hosts with different policies\");\n }\n\n if (hasSession == true) {\n const session = context.sessions.require((args.session as string).trim());\n return { profile: session.profile, session: session };\n }\n\n if (hasTarget == true) {\n const profile = requireProfile(context, (args.target as string).trim());\n return { profile: profile, session: null };\n }\n\n const onlyProfile = context.config.profiles.values().next().value;\n if (context.config.profiles.size === 1 && onlyProfile != null) {\n return { profile: onlyProfile, session: null };\n }\n\n if (context.config.profiles.size === 0) {\n throw new Error(`no host profiles are registered — set ${SINGLE_HOST_ENV.HOST} / ${SINGLE_HOST_ENV.USER} in this server's env block, then restart it`);\n }\n\n const available = Array.from(context.config.profiles.keys());\n throw new Error(`this server fronts several hosts, so 'target' is required (registered: ${available.join(\", \")})`);\n}\n\n/**\n * Runs `operation` against the resolved host.\n *\n * A session routes through `runExclusive`, which serializes work and keeps the idle\n * sweeper away; a `target` opens a one-off connection and closes it afterwards. The\n * connection is created but not dialled — `exec` / `withSftp` connect on demand, so a\n * command the guard refuses never costs a handshake.\n *\n * @throws {Error} If the one-off connection ceiling is reached.\n */\nexport async function withHostConnection<T>(\n profile: SshHostProfile,\n session: SshSession | null,\n operation: (connection: SshConnection) => Promise<T>\n): Promise<T> {\n if (session != null) {\n return await session.runExclusive(operation);\n }\n\n if (activeEphemeralCount >= MAX_EPHEMERAL_CONNECTIONS) {\n throw new Error(`too many concurrent one-off connections (${MAX_EPHEMERAL_CONNECTIONS}); open a session with ssh_connect and reuse it`);\n }\n\n activeEphemeralCount += 1;\n const connection = new SshConnection(profile);\n\n try {\n return await operation(connection);\n }\n finally {\n // Nested finally: a throwing disconnect must not leak the slot, or the ceiling\n // ratchets down until every call fails.\n try {\n connection.disconnect();\n }\n finally {\n activeEphemeralCount -= 1;\n }\n }\n}\n\n/**\n * Runtime-known local paths the file tools must refuse, on top of the built-in rules.\n * The loaded config is the critical one: overwriting it rewrites every guard in force.\n */\nexport function protectedLocalPathsOf(context: ToolContext): string[] {\n if (context.config.sourcePath == null) {\n return [];\n }\n\n return [context.config.sourcePath];\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\nimport { $logger } from \"@/_libs\";\nimport type { SshExecResult } from \"@/_types\";\n\nimport { formatExecResult } from \"./format\";\nimport { resolveProfile, textResult, toToolError, withHostConnection } from \"./tool-context\";\nimport type { ToolContext } from \"./tool-context\";\n\nexport function registerExecTools(server: McpServer, context: ToolContext): void {\n server.registerTool(\n \"ssh_exec\",\n {\n title: \"Run a command over SSH\",\n description: [\n \"Run a shell command on a registered SSH host and return stdout, stderr and the exit code.\",\n \"With a single configured host, no target is needed. Pass 'session' to reuse an open session (which remembers its working directory), or 'target' to pick a host when several are registered — one or the other, never both.\",\n \"A non-zero exit code is reported as normal output, not as a tool error — read the exit code and stderr to judge the outcome.\",\n \"Almost everything is permitted: package installs, service restarts, sudo, interpreters. Only catastrophic operations are refused outright (wiping the filesystem root, formatting a disk, rebooting, flushing the firewall), and individual profiles may add their own limits.\",\n ].join(\" \"),\n inputSchema: {\n command: z.string().min(1).describe(\"Shell command, exactly as it would be typed in a terminal. Chaining with ';', '&&', '||' and pipes is allowed; each part is screened separately.\"),\n target: z.string().optional().describe(\"Host profile alias. Omit it when this server fronts a single host, which is the usual setup. Opens a one-off connection that is closed afterwards.\"),\n session: z.string().optional().describe(\"Session id from ssh_connect. Reuses that connection and keeps the working directory across calls.\"),\n cwd: z.string().optional().describe(\"Absolute directory to run in, with no shell metacharacters. With a session, the session also moves there.\"),\n timeoutMs: z.number().int().positive().optional().describe(\"Lowers the command timeout for this call; it cannot exceed the profile's own limit. The channel is closed when it elapses; the remote process may survive.\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ command, target, session, cwd, timeoutMs }) => {\n let _logger = $logger.child({ context: \"ssh_exec\" });\n\n try {\n const { profile, session: openSession } = resolveProfile(context, { target: target, session: session });\n _logger = _logger.child({ profile: profile.name, session_id: openSession?.sessionId });\n\n // Clamped, not defaulted: a per-call override that could exceed the profile\n // ceiling would make the ceiling advisory.\n const requestedTimeoutMs = timeoutMs ?? profile.policy.execTimeoutMs;\n const effectiveTimeoutMs = Math.min(requestedTimeoutMs, profile.policy.execTimeoutMs);\n\n // An empty string is \"not specified\", not \"the root of nowhere\" — passing it\n // through would silently reset a session's tracked directory.\n let requestedCwd: string | undefined = undefined;\n if (cwd != null && cwd.trim() !== \"\") {\n requestedCwd = cwd.trim();\n }\n\n _logger.debug(\"running command\", { command: command, timeout_ms: effectiveTimeoutMs });\n\n let result: SshExecResult;\n if (openSession != null) {\n result = await openSession.exec(command, { cwd: requestedCwd, timeoutMs: effectiveTimeoutMs });\n }\n else {\n result = await withHostConnection(profile, null, async (connection) => {\n return await connection.exec({\n command: command,\n cwd: requestedCwd,\n timeoutMs: effectiveTimeoutMs,\n maxOutputCharacters: profile.policy.maxOutputCharacters,\n trackCwd: false,\n });\n });\n }\n\n _logger.info(\"command executed\", {\n exit_code: result.exitCode,\n duration_ms: result.durationMs,\n timed_out: result.timedOut,\n });\n\n const rendered = formatExecResult(result, effectiveTimeoutMs);\n return textResult(rendered);\n }\n catch (ex) {\n return toToolError(ex, \"ssh_exec\", command);\n }\n }\n );\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\nimport { $logger, expandHomePath, formatBytes } from \"@/_libs\";\nimport { GuardRejectionError, inspectLocalPath } from \"@/modules/guard\";\nimport {\n downloadFile,\n listRemoteDirectory,\n readRemoteFile,\n uploadFile,\n writeRemoteFile,\n} from \"@/modules/ssh\";\n\nimport { formatDirectoryListing } from \"./format\";\nimport {\n protectedLocalPathsOf,\n resolveProfile,\n textResult,\n toToolError,\n withHostConnection,\n} from \"./tool-context\";\nimport type { ToolContext } from \"./tool-context\";\n\nconst TARGET_DESCRIPTION = \"Host profile alias. Omit it when this server fronts a single host, which is the usual setup.\";\n\nconst SESSION_DESCRIPTION = \"Session id from ssh_connect, whose connection is reused. Pass this or 'target', not both.\";\n\n/**\n * Screens a path on the machine running this server.\n *\n * The remote side is guarded inside the SFTP layer, where the policy lives. The local\n * side has no policy — it is the operator's own filesystem — so it is checked here, at\n * the only layer that knows the path came from a tool argument.\n *\n * @throws {GuardRejectionError} If the path is protected.\n */\nfunction requirePermittedLocalPath(context: ToolContext, localPath: string, access: \"read\" | \"write\"): void {\n const verdict = inspectLocalPath(localPath, access, protectedLocalPathsOf(context));\n if (verdict.allowed == false) {\n throw new GuardRejectionError(verdict);\n }\n}\n\nexport function registerFileTools(server: McpServer, context: ToolContext): void {\n server.registerTool(\n \"ssh_list_dir\",\n {\n title: \"List a remote directory\",\n description: [\n \"List a directory on a registered SSH host over SFTP, with type, permissions, size and mtime.\",\n \"Cheaper and more structured than running 'ls -la' through ssh_exec, and it works on read-only profiles.\",\n ].join(\" \"),\n inputSchema: {\n path: z.string().min(1).describe(\"Absolute remote directory path. Profiles with allowedPaths set accept only paths inside them.\"),\n target: z.string().optional().describe(TARGET_DESCRIPTION),\n session: z.string().optional().describe(SESSION_DESCRIPTION),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ path: remotePath, target, session }) => {\n const _logger = $logger.child({ context: \"ssh_list_dir\", remote_path: remotePath });\n\n try {\n const { profile, session: openSession } = resolveProfile(context, { target: target, session: session });\n\n const listing = await withHostConnection(profile, openSession, async (connection) => {\n return await listRemoteDirectory(connection, remotePath);\n });\n\n _logger.info(\"remote directory listed\", {\n profile: profile.name,\n entry_count: listing.totalCount,\n truncated: listing.truncated,\n });\n const rendered = formatDirectoryListing(remotePath, listing);\n return textResult(rendered);\n }\n catch (ex) {\n return toToolError(ex, \"ssh_list_dir\", `list ${remotePath}`);\n }\n }\n );\n\n server.registerTool(\n \"ssh_read_file\",\n {\n title: \"Read a remote file\",\n description: [\n \"Read a remote text file over SFTP and return its contents.\",\n \"Oversized files come back truncated to their leading bytes rather than failing, so pointing this at a large log is safe.\",\n \"Files that report size 0 but hold content (/proc, /sys) are read in full up to the ceiling.\",\n ].join(\" \"),\n inputSchema: {\n path: z.string().min(1).describe(\"Absolute remote file path.\"),\n target: z.string().optional().describe(TARGET_DESCRIPTION),\n session: z.string().optional().describe(SESSION_DESCRIPTION),\n maxBytes: z.number().int().positive().optional().describe(\"Lowers the read ceiling for this call; it cannot exceed the profile's maxReadFileBytes.\"),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ path: remotePath, target, session, maxBytes }) => {\n const _logger = $logger.child({ context: \"ssh_read_file\", remote_path: remotePath });\n\n try {\n const { profile, session: openSession } = resolveProfile(context, { target: target, session: session });\n\n // Clamped, not defaulted: an override above the profile ceiling would let one\n // call buffer hundreds of megabytes and take the server down.\n const requestedLimit = maxBytes ?? profile.policy.maxReadFileBytes;\n const readLimit = Math.min(requestedLimit, profile.policy.maxReadFileBytes);\n\n const file = await withHostConnection(profile, openSession, async (connection) => {\n return await readRemoteFile(connection, remotePath, readLimit);\n });\n\n let header = `${remotePath} — ${formatBytes(file.readBytes)} read`;\n if (file.sizeBytes > 0) {\n header = `${remotePath} — ${formatBytes(file.sizeBytes)}`;\n }\n\n if (file.truncated == true) {\n header += `, truncated to the first ${formatBytes(file.readBytes)}`;\n }\n\n _logger.info(\"remote file read\", {\n profile: profile.name,\n size_bytes: file.sizeBytes,\n read_bytes: file.readBytes,\n truncated: file.truncated,\n });\n return textResult(`${header}\\n\\n${file.content}`);\n }\n catch (ex) {\n return toToolError(ex, \"ssh_read_file\", `read ${remotePath}`);\n }\n }\n );\n\n server.registerTool(\n \"ssh_write_file\",\n {\n title: \"Write a remote file\",\n description: [\n \"Write or append UTF-8 text to a file on a registered SSH host over SFTP.\",\n \"Use this instead of 'echo ... > file' through ssh_exec: no shell quoting to get wrong, and it works with multi-line content.\",\n \"Refused on read-only profiles. The parent directory must already exist.\",\n ].join(\" \"),\n inputSchema: {\n path: z.string().min(1).describe(\"Absolute remote file path. Existing content is replaced unless 'append' is true.\"),\n content: z.string().describe(\"UTF-8 text to write.\"),\n target: z.string().optional().describe(TARGET_DESCRIPTION),\n session: z.string().optional().describe(SESSION_DESCRIPTION),\n append: z.boolean().optional().describe(\"Append instead of replacing. Defaults to false.\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ path: remotePath, content, target, session, append }) => {\n const _logger = $logger.child({ context: \"ssh_write_file\", remote_path: remotePath });\n\n try {\n const { profile, session: openSession } = resolveProfile(context, { target: target, session: session });\n const shouldAppend = append ?? false;\n\n const writtenBytes = await withHostConnection(profile, openSession, async (connection) => {\n return await writeRemoteFile(connection, {\n remotePath: remotePath,\n content: content,\n append: shouldAppend,\n });\n });\n\n let verb = \"Wrote\";\n if (shouldAppend == true) {\n verb = \"Appended\";\n }\n\n _logger.info(\"remote file written\", { profile: profile.name, bytes: writtenBytes });\n return textResult(`${verb} ${formatBytes(writtenBytes)} to ${remotePath} on ${profile.name}.`);\n }\n catch (ex) {\n return toToolError(ex, \"ssh_write_file\", `write ${remotePath}`);\n }\n }\n );\n\n server.registerTool(\n \"ssh_upload\",\n {\n title: \"Upload a file over SFTP\",\n description: [\n \"Upload a local file to a registered SSH host over SFTP.\",\n \"Refused on read-only profiles, and for local paths holding credentials (SSH keys, cloud credentials, this server's own config).\",\n \"The remote parent directory must already exist.\",\n ].join(\" \"),\n inputSchema: {\n localPath: z.string().min(1).describe(\"Local file path on the machine running this MCP server. '~' is expanded.\"),\n remotePath: z.string().min(1).describe(\"Absolute destination path on the remote host, including the filename.\"),\n target: z.string().optional().describe(TARGET_DESCRIPTION),\n session: z.string().optional().describe(SESSION_DESCRIPTION),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ localPath, remotePath, target, session }) => {\n const _logger = $logger.child({ context: \"ssh_upload\", remote_path: remotePath });\n\n try {\n const { profile, session: openSession } = resolveProfile(context, { target: target, session: session });\n\n const resolvedLocalPath = expandHomePath(localPath);\n requirePermittedLocalPath(context, resolvedLocalPath, \"read\");\n\n if (fs.existsSync(resolvedLocalPath) == false) {\n return textResult(`local file not found: ${resolvedLocalPath}`);\n }\n\n const transferredBytes = await withHostConnection(profile, openSession, async (connection) => {\n return await uploadFile(connection, resolvedLocalPath, remotePath);\n });\n\n _logger.info(\"file uploaded\", { profile: profile.name, bytes: transferredBytes });\n return textResult(`Uploaded ${resolvedLocalPath} → ${remotePath} (${formatBytes(transferredBytes)}) on ${profile.name}.`);\n }\n catch (ex) {\n return toToolError(ex, \"ssh_upload\", `upload to ${remotePath}`);\n }\n }\n );\n\n server.registerTool(\n \"ssh_download\",\n {\n title: \"Download a file over SFTP\",\n description: [\n \"Download a file from a registered SSH host to the machine running this MCP server.\",\n \"Use this for binaries or files too large to read into the conversation; missing local directories are created.\",\n \"The local destination is overwritten, and paths holding credentials or this server's own configuration are refused.\",\n ].join(\" \"),\n inputSchema: {\n remotePath: z.string().min(1).describe(\"Absolute source path on the remote host.\"),\n localPath: z.string().min(1).describe(\"Local destination path, including the filename. '~' is expanded. Overwritten if it exists.\"),\n target: z.string().optional().describe(TARGET_DESCRIPTION),\n session: z.string().optional().describe(SESSION_DESCRIPTION),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ remotePath, localPath, target, session }) => {\n const _logger = $logger.child({ context: \"ssh_download\", remote_path: remotePath });\n\n try {\n const { profile, session: openSession } = resolveProfile(context, { target: target, session: session });\n\n const resolvedLocalPath = expandHomePath(localPath);\n requirePermittedLocalPath(context, resolvedLocalPath, \"write\");\n\n fs.mkdirSync(path.dirname(resolvedLocalPath), { recursive: true });\n\n const transferredBytes = await withHostConnection(profile, openSession, async (connection) => {\n return await downloadFile(connection, remotePath, resolvedLocalPath);\n });\n\n _logger.info(\"file downloaded\", { profile: profile.name, bytes: transferredBytes });\n return textResult(`Downloaded ${remotePath} → ${resolvedLocalPath} (${formatBytes(transferredBytes)}) from ${profile.name}.`);\n }\n catch (ex) {\n return toToolError(ex, \"ssh_download\", `download ${remotePath}`);\n }\n }\n );\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\nimport { $logger } from \"@/_libs\";\n\nimport { formatHostList } from \"./format\";\nimport { textResult, toToolError } from \"./tool-context\";\nimport type { ToolContext } from \"./tool-context\";\n\nexport function registerHostTools(server: McpServer, context: ToolContext): void {\n server.registerTool(\n \"ssh_list_hosts\",\n {\n title: \"List SSH host profiles\",\n description: [\n \"List the SSH hosts this server may connect to, with each host's guard policy.\",\n \"Call this first: every other tool takes a profile alias as its 'target', and no host outside this list can be reached.\",\n \"Credentials are never returned — only which auth method the profile uses.\",\n ].join(\" \"),\n inputSchema: {},\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async () => {\n const _logger = $logger.child({ context: \"ssh_list_hosts\" });\n\n try {\n const listing = formatHostList(context.config);\n _logger.debug(\"host list returned\", { profile_count: context.config.profiles.size });\n return textResult(listing);\n }\n catch (ex) {\n return toToolError(ex, \"ssh_list_hosts\", \"list hosts\");\n }\n }\n );\n\n server.registerTool(\n \"ssh_reload_config\",\n {\n title: \"Reload the host configuration\",\n description: [\n \"Re-read the host configuration and apply it, without restarting the MCP server.\",\n \"Use after the operator edits the config file — adding a host, tightening a policy.\",\n \"Every open session is closed first, so the new policy is in force everywhere rather than leaving old sessions on the old rules.\",\n \"Configuration supplied through environment variables is fixed for the life of the process; changing that still needs a restart.\",\n ].join(\" \"),\n inputSchema: {},\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async () => {\n const _logger = $logger.child({ context: \"ssh_reload_config\" });\n\n try {\n const previousLabel = context.config.sourceLabel;\n const closedSessions = context.sessions.list().length;\n\n // Closed before the swap: a session created under the old policy would\n // otherwise keep running on it, so \"reloaded\" would be only half true.\n context.sessions.closeAll();\n\n const reloaded = context.reloadConfig();\n\n const lines: string[] = [\n `Reloaded ${reloaded.profiles.size} host profile(s) from ${reloaded.sourceLabel}.`,\n ];\n\n if (reloaded.profiles.size > 0) {\n lines.push(`Hosts: ${Array.from(reloaded.profiles.keys()).join(\", \")}`);\n }\n\n if (closedSessions > 0) {\n lines.push(`Closed ${closedSessions} open session(s); reopen with ssh_connect if needed.`);\n }\n\n if (reloaded.sourcePath == null) {\n lines.push(\"This config comes from environment variables, which cannot change while the server runs — restart the MCP server to apply edits to them.\");\n }\n\n _logger.info(\"config reloaded\", {\n profile_count: reloaded.profiles.size,\n previous_source: previousLabel,\n config_source: reloaded.sourceLabel,\n });\n\n return textResult(lines.join(\"\\n\"));\n }\n catch (ex) {\n return toToolError(ex, \"ssh_reload_config\", \"reload the configuration\");\n }\n }\n );\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\nimport { $logger } from \"@/_libs\";\n\nimport { formatSessionList } from \"./format\";\nimport { errorResult, resolveProfile, textResult, toToolError } from \"./tool-context\";\nimport type { ToolContext } from \"./tool-context\";\n\nexport function registerSessionTools(server: McpServer, context: ToolContext): void {\n server.registerTool(\n \"ssh_connect\",\n {\n title: \"Open an SSH session\",\n description: [\n \"Open a reusable SSH session to a registered host and return its session id.\",\n \"Prefer this over one-off 'target' calls when running several commands: it pays the handshake once and remembers the working directory, so a 'cd' in one ssh_exec still applies to the next.\",\n \"Close it with ssh_disconnect when done; idle sessions are reaped automatically, and a session whose connection drops reports that rather than silently reconnecting.\",\n ].join(\" \"),\n inputSchema: {\n target: z.string().optional().describe(\"Host profile alias. Omit it when this server fronts a single host, which is the usual setup.\"),\n cwd: z.string().optional().describe(\"Absolute directory to start in, with no shell metacharacters. Defaults to the profile's defaultCwd, else the login shell's directory.\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ target, cwd }) => {\n let _logger = $logger.child({ context: \"ssh_connect\", target: target });\n\n // Tracked outside the try so a probe that *throws* still tears the session\n // down — leaking it would burn one of the 32 slots until the sweeper ran.\n let openedSessionId: string | null = null;\n\n try {\n const { profile } = resolveProfile(context, { target: target });\n const session = await context.sessions.open(profile);\n openedSessionId = session.sessionId;\n _logger = _logger.child({ session_id: session.sessionId });\n\n if (cwd != null && cwd.trim() !== \"\") {\n session.cwd = cwd.trim();\n }\n\n // One `pwd` settles the real starting directory (and proves `cwd` exists),\n // so the session reports a concrete path instead of \"login default\".\n const probe = await session.exec(\"pwd\");\n\n // `exitCode === null` means the channel closed with no exit status — the\n // probe never proved anything, so it counts as a failure rather than a pass.\n const probeSucceeded = probe.exitCode === 0 && probe.timedOut == false;\n if (probeSucceeded == false) {\n context.sessions.close(session.sessionId);\n openedSessionId = null;\n _logger.warn(\"session probe failed, closing the session\", {\n exit_code: probe.exitCode,\n timed_out: probe.timedOut,\n stderr: probe.stderr,\n });\n return errorResult(`ssh_connect failed: could not confirm the starting directory.\\n${probe.stderr.trim()}`);\n }\n\n const lines: string[] = [\n `Opened session ${session.sessionId} → ${profile.username}@${profile.host}:${profile.port}`,\n `cwd: ${session.cwd}`,\n ];\n\n if (profile.policy.readonly == true) {\n lines.push(\"This profile is READ-ONLY: writes, redirections and uploads will be rejected.\");\n }\n\n lines.push(`Run commands with ssh_exec({ session: \"${session.sessionId}\", command: \"...\" }).`);\n\n _logger.info(\"session opened via tool\", { cwd: session.cwd });\n return textResult(lines.join(\"\\n\"));\n }\n catch (ex) {\n if (openedSessionId != null) {\n context.sessions.close(openedSessionId);\n }\n\n return toToolError(ex, \"ssh_connect\", `connect to ${target ?? \"the configured host\"}`);\n }\n }\n );\n\n server.registerTool(\n \"ssh_disconnect\",\n {\n title: \"Close an SSH session\",\n description: \"Close an open SSH session and release its connection.\",\n inputSchema: {\n session: z.string().describe(\"Session id returned by ssh_connect.\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ session }) => {\n const _logger = $logger.child({ context: \"ssh_disconnect\", session_id: session });\n\n try {\n const closed = context.sessions.close(session);\n if (closed == false) {\n return errorResult(`no open session with id '${session}'. Call ssh_list_sessions to see what is open.`);\n }\n\n _logger.info(\"session closed via tool\");\n return textResult(`Closed session ${session}.`);\n }\n catch (ex) {\n return toToolError(ex, \"ssh_disconnect\", `close ${session}`);\n }\n }\n );\n\n server.registerTool(\n \"ssh_list_sessions\",\n {\n title: \"List open SSH sessions\",\n description: \"List every open SSH session with its host, working directory and idle time.\",\n inputSchema: {},\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n },\n async () => {\n try {\n const sessions = context.sessions.list();\n const rendered = formatSessionList(sessions);\n return textResult(rendered);\n }\n catch (ex) {\n return toToolError(ex, \"ssh_list_sessions\", \"list sessions\");\n }\n }\n );\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\nimport { registerExecTools } from \"./exec-tools\";\nimport { registerFileTools } from \"./file-tools\";\nimport { registerHostTools } from \"./host-tools\";\nimport { registerSessionTools } from \"./session-tools\";\nimport type { ToolContext } from \"./tool-context\";\n\nexport { registerHostTools } from \"./host-tools\";\nexport { registerSessionTools } from \"./session-tools\";\nexport { registerExecTools } from \"./exec-tools\";\nexport { registerFileTools } from \"./file-tools\";\n\nexport {\n textResult,\n errorResult,\n describeError,\n toToolError,\n requireProfile,\n resolveProfile,\n withHostConnection,\n protectedLocalPathsOf,\n} from \"./tool-context\";\nexport type { ToolContext } from \"./tool-context\";\n\nexport {\n formatHostList,\n formatExecResult,\n formatGuardRejection,\n formatSessionList,\n formatDirectoryListing,\n} from \"./format\";\n\n/** Registers every tool this server exposes, in the order the model should discover them. */\nexport function registerAllTools(server: McpServer, context: ToolContext): void {\n registerHostTools(server, context);\n registerSessionTools(server, context);\n registerExecTools(server, context);\n registerFileTools(server, context);\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\nimport { SERVER_NAME, SERVER_VERSION } from \"@/_defs\";\nimport { $logger } from \"@/_libs\";\nimport type { SshMcpConfig } from \"@/_types\";\nimport { loadConfig } from \"@/modules/config\";\nimport { SshSessionManager } from \"@/modules/ssh\";\nimport { registerAllTools } from \"@/modules/tools\";\nimport type { ToolContext } from \"@/modules/tools\";\n\nexport interface SshMcpServerOptions {\n /** Explicit config path; otherwise `SSH_MCP_CONFIG`, then the home-directory candidates. */\n configPath?: string;\n}\n\nexport interface SshMcpServerInstance {\n server: McpServer;\n sessions: SshSessionManager;\n /** Always the config currently in force, including after a reload. */\n readonly config: SshMcpConfig;\n /**\n * Re-reads the config source and applies it.\n *\n * @throws {Error} If the source is now missing or malformed; the previous config\n * stays in force in that case.\n */\n reloadConfig(): SshMcpConfig;\n /** Stops the sweeper and closes every open session. Call before the process exits. */\n shutdown(): void;\n}\n\n/** Handed to the client on connect, so the model knows the workflow before its first call. */\nconst SERVER_INSTRUCTIONS = [\n \"This server runs shell commands and transfers files on remote hosts over SSH.\",\n \"Only hosts pre-registered in a local config file are reachable — arbitrary host/credential arguments are not accepted.\",\n \"\",\n \"Usually one server entry fronts one host, so no 'target' argument is needed — omit it and the configured host is used. ssh_list_hosts shows what is registered and what it permits.\",\n \"\",\n \"Workflow:\",\n \"1. One command: ssh_exec with just 'command'.\",\n \"2. Several commands in a row: ssh_connect once, then ssh_exec with 'session' (the working directory persists across calls), then ssh_disconnect.\",\n \"3. Files: ssh_list_dir, ssh_read_file, ssh_write_file, ssh_upload, ssh_download — prefer these over shell equivalents; no quoting to get wrong.\",\n \"Pass 'target' only when ssh_list_hosts shows several hosts, and never together with 'session'.\",\n \"\",\n \"What is permitted: ordinary administration, without asking — package installs, service restarts, sudo, interpreters, config edits, deployments.\",\n \"Refused on every profile, and only these: operations that destroy the machine or cut this connection — wiping the filesystem root or a system directory, deleting a file the host cannot boot without, formatting a disk, writing raw bytes to a block device, rebooting or powering off, flushing the firewall, removing every cron job.\",\n \"Individual profiles may add their own limits (read-only, an allow-list, deny patterns, path restrictions). ssh_list_hosts shows which apply where.\",\n \"\",\n \"Commands run with no terminal and with stdin closed, so anything that waits for input fails immediately instead of hanging: use non-interactive flags (apt-get -y, sudo -n), 'top -bn1' rather than 'top', and ssh_write_file rather than an editor.\",\n \"A job that may outlive its timeout should be started detached (nohup … &, tmux new -d) and polled through its log.\",\n \"\",\n \"A guard rejection is a policy decision, not a transient failure — do not retry the same command; report it and ask before working around it.\",\n \"A non-zero exit code is returned as normal output; read it and stderr to judge what happened.\",\n \"You still carry the judgement the guards do not: these are real hosts, and an irreversible action deserves a check with the operator first.\",\n].join(\"\\n\");\n\n/**\n * Builds the MCP server: loads host profiles, wires the session manager, registers tools.\n *\n * Transport is deliberately left to the caller — `cli.ts` attaches stdio, tests can attach\n * an in-memory pair.\n *\n * @throws {Error} If a config file exists but is malformed (a bad policy field must not\n * silently degrade into \"no guard\").\n */\nexport function createSshMcpServer(options?: SshMcpServerOptions): SshMcpServerInstance {\n const _logger = $logger.child({ context: \"createSshMcpServer\" });\n\n const config = loadConfig(options?.configPath);\n\n const sessions = new SshSessionManager();\n sessions.startIdleSweeper();\n\n const server = new McpServer(\n {\n name: SERVER_NAME,\n version: SERVER_VERSION,\n },\n {\n instructions: SERVER_INSTRUCTIONS,\n }\n );\n\n // The tools hold this object, not the config value, so a reload is visible to every\n // already-registered handler without re-registering anything.\n const context: ToolContext = {\n config: config,\n sessions: sessions,\n reloadConfig(): SshMcpConfig {\n const reloaded = loadConfig(options?.configPath);\n context.config = reloaded;\n return reloaded;\n },\n };\n\n registerAllTools(server, context);\n\n _logger.info(\"mcp server built\", {\n profile_count: config.profiles.size,\n config_source: config.sourceLabel,\n });\n\n return {\n server: server,\n sessions: sessions,\n get config(): SshMcpConfig {\n return context.config;\n },\n reloadConfig(): SshMcpConfig {\n return context.reloadConfig();\n },\n shutdown(): void {\n sessions.stopIdleSweeper();\n sessions.closeAll();\n },\n };\n}\n","#!/usr/bin/env node\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nimport { CONFIG_PATH_ENV, DEFAULT_CONFIG_FILENAMES, LOG_LEVEL_ENV, SERVER_NAME, SERVER_VERSION } from \"@/_defs\";\nimport { $logger } from \"@/_libs\";\nimport type { SshHostProfile, SshMcpConfig } from \"@/_types\";\nimport { SshConnection } from \"@/modules/ssh\";\nimport { createSshMcpServer } from \"@/server\";\n\ninterface CliArguments {\n configPath?: string;\n showHelp: boolean;\n showVersion: boolean;\n checkOnly: boolean;\n}\n\nfunction parseArguments(argv: string[]): CliArguments {\n const parsed: CliArguments = { showHelp: false, showVersion: false, checkOnly: false };\n\n for (let index = 0; index < argv.length; index++) {\n const argument = argv[index];\n\n if (argument === \"--help\" || argument === \"-h\") {\n parsed.showHelp = true;\n continue;\n }\n\n if (argument === \"--version\" || argument === \"-v\") {\n parsed.showVersion = true;\n continue;\n }\n\n if (argument === \"--check\") {\n parsed.checkOnly = true;\n continue;\n }\n\n // A missing value must fail loudly: falling through to the env var or the home\n // directory would start the server against a *different* set of host policies\n // than the operator named, with nothing in the output saying so.\n if (argument === \"--config\" || argument === \"-c\") {\n const value = argv[index + 1];\n if (value == null || value.startsWith(\"-\") == true) {\n throw new Error(`${argument} requires a file path`);\n }\n\n parsed.configPath = value;\n index++;\n continue;\n }\n\n if (argument.startsWith(\"--config=\") == true) {\n const value = argument.slice(\"--config=\".length);\n if (value === \"\") {\n throw new Error(\"--config= requires a file path\");\n }\n\n parsed.configPath = value;\n continue;\n }\n }\n\n return parsed;\n}\n\nconst HELP_TEXT = [\n `${SERVER_NAME} ${SERVER_VERSION} — MCP server for SSH command execution and SFTP transfers`,\n \"\",\n \"Usage:\",\n \" akms-ssh [--config <path>]\",\n \"\",\n \"Options:\",\n \" -c, --config <path> Host profile config file\",\n ` (default: ${CONFIG_PATH_ENV} env var, else ~/${DEFAULT_CONFIG_FILENAMES[0]})`,\n \" --check Connect to every profile, report the result, and exit.\",\n \" Prints each host key fingerprint so it can be pinned.\",\n \" -v, --version Print the version and exit\",\n \" -h, --help Print this help and exit\",\n \"\",\n \"Environment:\",\n ` ${CONFIG_PATH_ENV} Host profiles as JSON, or a path to a JSON file.`,\n \" A value starting with '{' is read as the config itself, so an\",\n \" MCP client can carry the whole setup in its own env block.\",\n ` ${LOG_LEVEL_ENV} silent | debug | info | warn | error (default: info, written to stderr)`,\n \"\",\n \"The server speaks MCP over stdio; run it from an MCP client, not interactively.\",\n].join(\"\\n\");\n\n/**\n * Connects to every profile and reports what happened.\n *\n * Without this the only way to find out whether a config works is to ask an agent to try\n * something, which mixes a setup mistake up with a policy rejection. Writes to stdout\n * because this mode is not an MCP session.\n *\n * @returns Process exit code: 0 when every profile connected.\n */\n/**\n * How a profile will authenticate, including the key path.\n *\n * The path is shown here but withheld from the runtime error message: `--check` is run by\n * the operator on their own terminal, whereas that message is handed to a model.\n */\nfunction describeAuth(profile: SshHostProfile): string {\n if (profile.privateKeyPath != null) {\n return `key ${profile.privateKeyPath}`;\n }\n\n if (profile.privateKey != null) {\n return \"inline key\";\n }\n\n if (profile.password != null) {\n return \"password\";\n }\n\n return \"ssh agent\";\n}\n\nasync function runConnectionCheck(config: SshMcpConfig): Promise<number> {\n if (config.profiles.size === 0) {\n process.stdout.write(`No host profiles are registered (config source: ${config.sourceLabel}).\\n`);\n return 1;\n }\n\n process.stdout.write(`Checking ${config.profiles.size} profile(s) from ${config.sourceLabel}\\n\\n`);\n\n const profiles = Array.from(config.profiles.values());\n const results = await Promise.all(profiles.map(async (profile) => {\n const connection = new SshConnection(profile);\n const startedAt = Date.now();\n\n try {\n await connection.connect();\n return {\n profile: profile,\n connected: true,\n durationMs: Date.now() - startedAt,\n fingerprint: connection.hostKeyFingerprint,\n detail: \"\",\n };\n }\n catch (ex) {\n let detail = String(ex);\n if (ex instanceof Error) {\n detail = ex.message;\n }\n\n return {\n profile: profile,\n connected: false,\n durationMs: Date.now() - startedAt,\n fingerprint: connection.hostKeyFingerprint,\n detail: detail,\n };\n }\n finally {\n connection.disconnect();\n }\n }));\n\n let connectedCount = 0;\n for (const result of results) {\n const endpoint = `${result.profile.username}@${result.profile.host}:${result.profile.port}`;\n const auth = describeAuth(result.profile);\n\n if (result.connected == true) {\n connectedCount += 1;\n process.stdout.write(` OK ${result.profile.name} → ${endpoint} (${auth}, ${result.durationMs}ms)\\n`);\n }\n else {\n process.stdout.write(` FAILED ${result.profile.name} → ${endpoint} (${auth})\\n`);\n process.stdout.write(` ${result.detail}\\n`);\n }\n\n if (result.fingerprint != null) {\n let pinNote = \"not pinned — add it as hostKeyFingerprint to detect a changed key\";\n if (result.profile.hostKeyFingerprint != null) {\n pinNote = \"pinned\";\n }\n\n process.stdout.write(` host key ${result.fingerprint} (${pinNote})\\n`);\n }\n }\n\n process.stdout.write(`\\n${connectedCount} of ${results.length} reachable\\n`);\n\n if (connectedCount === results.length) {\n return 0;\n }\n\n return 1;\n}\n\nasync function main(): Promise<void> {\n const _logger = $logger.child({ context: \"cli\" });\n\n const cliArguments = parseArguments(process.argv.slice(2));\n\n if (cliArguments.showHelp == true) {\n process.stderr.write(`${HELP_TEXT}\\n`);\n return;\n }\n\n if (cliArguments.showVersion == true) {\n process.stderr.write(`${SERVER_VERSION}\\n`);\n return;\n }\n\n // `--check` prints a report a person reads; interleaved log lines make it unreadable.\n // An explicit level still wins, so `SSH_MCP_LOG_LEVEL=debug --check` stays available\n // for diagnosing a connection that fails for an unclear reason.\n if (cliArguments.checkOnly == true && process.env[LOG_LEVEL_ENV] == null) {\n process.env[LOG_LEVEL_ENV] = \"silent\";\n }\n\n const instance = createSshMcpServer({ configPath: cliArguments.configPath });\n\n if (cliArguments.checkOnly == true) {\n const exitCode = await runConnectionCheck(instance.config);\n instance.shutdown();\n process.exit(exitCode);\n }\n\n let shuttingDown = false;\n const shutdown = (signal: string): void => {\n if (shuttingDown == true) {\n return;\n }\n shuttingDown = true;\n\n _logger.info(\"shutting down\", { signal: signal });\n instance.shutdown();\n void instance.server.close().finally(() => {\n process.exit(0);\n });\n };\n\n process.on(\"SIGINT\", () => {\n shutdown(\"SIGINT\");\n });\n process.on(\"SIGTERM\", () => {\n shutdown(\"SIGTERM\");\n });\n\n // stdin closing means the MCP client is gone; without this the process would linger\n // holding every open SSH connection.\n process.stdin.on(\"close\", () => {\n shutdown(\"stdin-close\");\n });\n\n const transport = new StdioServerTransport();\n await instance.server.connect(transport);\n\n _logger.info(\"mcp server ready on stdio\", {\n server: SERVER_NAME,\n version: SERVER_VERSION,\n config_source: instance.config.sourceLabel,\n profile_count: instance.config.profiles.size,\n });\n}\n\nmain().catch((error: unknown) => {\n const _logger = $logger.child({ context: \"cli\" });\n _logger.error(error, \"mcp server failed to start\");\n\n // Printed independently of the logger: `--check` silences it, and a config mistake\n // that exits 1 with no explanation is the worst possible first-run experience.\n let detail = String(error);\n if (error instanceof Error) {\n detail = error.message;\n }\n\n process.stderr.write(`akms-ssh: ${detail}\\n`);\n process.exit(1);\n});\n"]}