ssh: fix sudo failing with "password required" (v6 / 1.1.0)
The connector asked for a sudo password on every privileged call and failed whenever nobody answered it, which is every unattended run. - Always probe `sudo -n` first, even for aliases set to sudo="prompt". `_sudo_prefix` used to elicit unconditionally, so a host granting this user NOPASSWD still opened an Agent Inbox prompt; with no human there it hit the client's 300s ELICITATION_DEADLINE, got back `cancel`, and surfaced as "sudo password required (user declined or timed out)". sudo refuses before running anything when it wants a password, so the probe is side-effect free. - Strip a leading `sudo` from `command` and turn it into sudo=true. Agents write `exec(command="sudo systemctl restart x")`: with sudo=false that ran a tty-less sudo, with sudo=true it nested `sudo -S ... sudo ...` whose inner prompt had no tty either. Handles -u/-n/-S/-E/-H/-i/-k/-p/--; an unknown flag leaves the command alone. sudo_user now implies sudo=true. - Run privileged commands as `sh -c '<command>'`, so `&&`, pipes and redirections are elevated too instead of only the first word. - Add SSH_MCP_SUDO_PASSWORD (optional, secret) for unattended runs. It is consulted only after `sudo -n` proved a password is needed, so on a NOPASSWD host it never lands in the command's own stdin. - Actionable errors for every sudo failure mode, and a `hint` on a nested sudo we could not peel off. General review of the same server: - Drain stdout and stderr together and make timeout_sec a real wall-clock deadline. Both streams share one SSH channel window, so reading stdout to EOF first stalled once a chatty stderr filled it. Command stdin is now closed after the optional password. - Queue messages that arrive while awaiting an elicitation reply instead of discarding them, so a concurrent tools/call is not lost. - Record the client's `elicitation` capability at initialize and fail fast when it is absent rather than blocking on a prompt nobody can answer. - Tolerate null/string integer arguments (depth, max_results, context_lines, timeout_sec). - Realign the version across both manifests: fragment.json said 5/1.0.4 while connector.json said 2/1.0.1, so the feed was permanently ahead of the installed version and offered an update forever. Also lands the pending docs work: CONNECTOR_MANIFEST_GUIDE.md as the single source of truth, docs/connector.manifest_guide.md retired to a pointer, CLAUDE.md audited against the repo, compile.py docstring fixed, and an opencode.json config.
This commit is contained in:
@@ -63,6 +63,14 @@
|
||||
"required": false,
|
||||
"secret": true,
|
||||
"example": ""
|
||||
},
|
||||
{
|
||||
"name": "SSH_MCP_SUDO_PASSWORD",
|
||||
"label": "Sudo password (non-interactive override)",
|
||||
"description": "Sudo password used when the remote host demands one and nobody can answer the Agent Inbox prompt (unattended/scheduled runs). Leave empty to always ask interactively. Only used after 'sudo -n' has proved the host really requires a password.",
|
||||
"required": false,
|
||||
"secret": true,
|
||||
"example": ""
|
||||
}
|
||||
],
|
||||
"setup_instructions": [
|
||||
@@ -90,7 +98,8 @@
|
||||
"SSH_MCP_CONNECT_TIMEOUT": "{ENV:SSH_MCP_CONNECT_TIMEOUT}",
|
||||
"SSH_MCP_LOGIN_PW_TTL": "{ENV:SSH_MCP_LOGIN_PW_TTL}",
|
||||
"SSH_MCP_SUDO_PW_TTL": "{ENV:SSH_MCP_SUDO_PW_TTL}",
|
||||
"SSH_MCP_KEY_PASSPHRASE": "{SECRET:SSH_MCP_KEY_PASSPHRASE}"
|
||||
"SSH_MCP_KEY_PASSPHRASE": "{SECRET:SSH_MCP_KEY_PASSPHRASE}",
|
||||
"SSH_MCP_SUDO_PASSWORD": "{SECRET:SSH_MCP_SUDO_PASSWORD}"
|
||||
}
|
||||
},
|
||||
"homepage": "",
|
||||
@@ -109,7 +118,7 @@
|
||||
"auth": {
|
||||
"type": "none"
|
||||
},
|
||||
"version": 2,
|
||||
"version_string": "1.0.1",
|
||||
"version_release_date": "2026-07-21"
|
||||
"version": 6,
|
||||
"version_string": "1.1.0",
|
||||
"version_release_date": "2026-09-03"
|
||||
}
|
||||
Reference in New Issue
Block a user