Files
my-pi/pi-ssh/extension-spec.md
T

119 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# pi-ssh extension specification
## Goal
Pi and its default tools remain local. Explicit collision-free tools perform selected operations on one configured remote server:
- `ssh_read`
- `ssh_write`
- `ssh_edit`
- `ssh_find`
- `ssh_grep`
- `ssh_bash`
The extension is for operating servers from local projects, not for replacing Pi's local workspace. It never auto-loads remote project instructions.
## Connection model
Runtime communication uses Node `ssh2` only. OpenSSH is not spawned during Pi sessions. A user must explicitly import a concrete OpenSSH alias before connecting:
```text
ssh_config.sh import <alias>
→ ssh -G <alias>
→ user chooses private-key or password auth
→ ssh2 obtains host key, user confirms fingerprint
→ ssh2 verifies authentication
→ encrypted vault is updated
```
The resulting host ID is the only runtime selector:
```text
/ssh <host-id>[:/absolute/path]
pi --ssh <host-id>[:/absolute/path]
```
Arbitrary `user@host`, port overrides, ProxyJump, and ProxyCommand are not supported in the first pure-ssh2 version. Unsupported imported configuration is rejected rather than ignored.
## Vault
Default paths:
```text
${XDG_CONFIG_HOME:-$HOME/.config}/my-pi/pi-ssh/hosts.enc
${XDG_CONFIG_HOME:-$HOME/.config}/my-pi/pi-ssh/vault.key
```
The directory is mode `700` and files are mode `600` on POSIX. A random adjacent 256-bit key encrypts and authenticates the complete validated configuration with AES-256-GCM. Each write uses a fresh IV and atomic replacement; plaintext is never written to a temporary file.
The adjacent-key design prevents casual disclosure of `hosts.enc` alone but does not protect against code able to read both files as the same local user.
The encrypted payload includes endpoint, authentication data, host groups, default cwd, and a pinned SHA256 host-key fingerprint. Private keys remain in their original paths; only their path and optional passphrase are stored.
## Authentication
Supported methods:
- password;
- single-password keyboard-interactive;
- OpenSSH private key;
- encrypted private key with passphrase.
Passwords, passphrases, private-key contents, vault key, and decrypted configuration must never enter command arguments, logs, permission evidence, system prompts, or Pi session entries.
## Host-key verification
Import displays the observed host-key algorithm and SHA256 fingerprint for explicit confirmation. Runtime `hostVerifier` must compare the server key with the pinned fingerprint and fail closed on any mismatch. Key changes require explicit host update.
## Transport
One persistent `ssh2.Client` belongs to the active host. Connection loss fails closed and no operation is automatically replayed.
### Shell
`ssh_bash` and explicit user `!` commands open exec channels. Commands run through `bash -lc` after changing to the selected remote cwd. Output streams through the normal Pi Bash operations callback. Abort or timeout closes the channel without reconnecting or replaying.
### Files
SFTP implements file operations:
- read and access checks;
- recursive directory creation;
- remote write through a temporary file;
- atomic OpenSSH rename extension when available;
- safe direct-write fallback when SFTP v3 cannot replace an existing target.
Remote paths map from Pi's local factory cwd into the selected remote cwd, but permission-system access extractors prevent those paths from entering local path normalization.
### Search
Search tools execute one capability-adaptive, bounded shell pipeline inside the already approved tool call. They never install or upload binaries.
- `ssh_find`: `fd``fdfind``git ls-files``find`; fixed filename/path substring semantics.
- `ssh_grep`: `rg``git grep``find -exec grep`; literal case-insensitive semantics by default.
- each backend emits at most `limit + 1` lines so truncation is explicit; public `limit` is 1200; each returned line is capped.
- relative paths resolve against remote cwd and `~/` against remote home.
- user strings are single-quoted as shell arguments and NUL/newline input is rejected.
- capability detection occurs only within the reviewed search call.
- search output is normalized by `pi-ssh` and excluded from RTK compaction.
Direct search commands remain denied through `ssh_bash`; structured search tools are the authoritative remote search surface.
## Permission boundary
There is one permission gate: `pi-permission-system`.
- `ssh_read`, `ssh_write`, `ssh_edit`, `ssh_find`, and `ssh_grep` default to `ask`.
- `ssh_bash` is a Bash-semantic `shellTools` alias with `decisionFloor: "ask"`.
- Bash hard denies remain denies.
- All asks enter the configured authorizer chain.
- Permission service absence or bridge registration failure must not install a permissive fallback.
Evidence includes configured host ID, endpoint, port, remote cwd, and a bounded operation summary, never credentials.
## Session and UI
The session stores only host ID, remote cwd, and remote home. Resume reloads current vault data and establishes a new ssh2 connection; failures fall back to local mode. `/ssh off` disposes the client and clears the status line.
The system prompt states that default tools are local and `ssh_*` tools are remote. It does not include remote file content.