@hahahhh/sshx 0.0.3 → 0.0.4-rc.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/README.md +75 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
**sshx** is a drop-in wrapper around OpenSSH. Wrap it as `alias ssh=sshx` and your existing SSH workflow works exactly as before — every flag, config, and connection passes through verbatim. But when you connect to a host (or Docker container) with sshx-aware features enabled, you unlock a persistent, shared remote server that gives you:
|
|
6
6
|
|
|
7
7
|
- 🔄 **Reverse command bridge** — run `sshx local <cmd>` *on the remote* to execute commands on your local machine, with stdout, stderr, exit code, and stdin all propagated.
|
|
8
|
+
- 📁 **Bidirectional workspace mount** — opt in to make the command initiator's current directory available to commands running on the other side.
|
|
8
9
|
- 🔌 **Automatic port forwarding** — remote local listeners (loopback `127.0.0.1` and wildcard `0.0.0.0`; e.g., a dev server on `0.0.0.0:8080` or `localhost:8080`) are automatically detected and forwarded to your local machine.
|
|
9
10
|
- 🌐 **Local domain binding** — access forwarded ports as `<host>.<your-user>.sshx:<port>` in your local browser, no manual `-L` flags needed.
|
|
10
11
|
- 🐳 **Docker container support** — target running containers by name or ID: `sshx my-container`. Command bridge support works inside containers via `docker exec`.
|
|
@@ -59,6 +60,69 @@ sshx local --timeout=30 npm test
|
|
|
59
60
|
- Commands have no implicit deadline. Put `--timeout=<duration>` immediately after the target to opt in; bare numbers mean seconds, and values such as `500ms`, `30s`, and `2m` are accepted. Timed-out commands exit with status 124.
|
|
60
61
|
- Policy: a configurable deny list controls which commands are blocked.
|
|
61
62
|
|
|
63
|
+
### 📁 Bidirectional Workspace Mount (opt-in, beta)
|
|
64
|
+
|
|
65
|
+
Set `features.remoteFs: true` to expose the command initiator's current directory through a read-write FUSE mount:
|
|
66
|
+
|
|
67
|
+
- `sshx remote <cmd>` starts the remote command in a mounted view of the local current directory.
|
|
68
|
+
- An interactive `sshx remote` shell still starts in the remote home. `SSHX_WORKSPACE` points to the mounted local workspace.
|
|
69
|
+
- From that shell, `sshx local <cmd>` mounts the remote current directory locally and starts the local command there.
|
|
70
|
+
- Writes and `fsync` are sent to the source immediately. Metadata and directory entries use short TTLs and are revalidated when files are reopened.
|
|
71
|
+
|
|
72
|
+
FUSE is a hard dependency when this feature is enabled: a mount failure aborts the command even when `strict` is false. Linux needs `/dev/fuse` plus `fusermount`/`fusermount3`; macOS needs a current macFUSE installation and is currently beta. The remote target must be Linux with FUSE available.
|
|
73
|
+
|
|
74
|
+
#### FUSE setup
|
|
75
|
+
|
|
76
|
+
The machine receiving the mounted view needs a working FUSE runtime. The Linux target therefore always needs FUSE for `sshx remote`; a macOS client also needs macFUSE when a remote shell runs `sshx local` and mounts the remote working directory back on the Mac.
|
|
77
|
+
|
|
78
|
+
**Linux target/client**
|
|
79
|
+
|
|
80
|
+
Install the FUSE 3 userspace tools (the kernel normally already includes the FUSE driver):
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
# Debian / Ubuntu
|
|
84
|
+
sudo apt-get update && sudo apt-get install -y fuse3
|
|
85
|
+
|
|
86
|
+
# Fedora / RHEL-family
|
|
87
|
+
sudo dnf install -y fuse3
|
|
88
|
+
|
|
89
|
+
# Arch Linux
|
|
90
|
+
sudo pacman -S fuse3
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Verify both the device and unmount helper:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
test -r /dev/fuse && test -w /dev/fuse
|
|
97
|
+
command -v fusermount3 || command -v fusermount
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If `/dev/fuse` is missing on a normal Linux host, load the kernel module with `sudo modprobe fuse`. Containers and restricted VMs must also expose `/dev/fuse` and permit FUSE mounts; installing `fuse3` alone is not sufficient. Docker targets are not supported by `remoteFs` yet.
|
|
101
|
+
|
|
102
|
+
**macOS client (current sshx backend)**
|
|
103
|
+
|
|
104
|
+
Install the latest macFUSE release from [macfuse.io](https://macfuse.io/) (recommended by the macFUSE project) or with `brew install --cask macfuse`. The current sshx implementation uses macFUSE's kernel/VFS backend.
|
|
105
|
+
|
|
106
|
+
On Apple Silicon, first-time kernel-backend setup requires:
|
|
107
|
+
|
|
108
|
+
1. Shut down, then hold the power/Touch ID button to enter macOS Recovery.
|
|
109
|
+
2. Open Startup Security Utility, select the system volume, and choose **Reduced Security**.
|
|
110
|
+
3. Enable **Allow user management of kernel extensions from identified developers**, then restart.
|
|
111
|
+
4. In **System Settings → Privacy & Security**, allow the macFUSE system software when prompted, then restart again.
|
|
112
|
+
|
|
113
|
+
Intel Macs do not need the Startup Security Utility change, but may still require approving macFUSE in Privacy & Security and restarting. macFUSE does not require disabling SIP or Gatekeeper.
|
|
114
|
+
|
|
115
|
+
After approval, trigger a mount once and verify that macFUSE loaded:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
ls /Library/Filesystems/macfuse.fs
|
|
119
|
+
ls /dev/macfuse*
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**macOS 15.4+ FSKit note:** macFUSE 5 provides a userspace FSKit backend that does not require a kernel extension, Recovery-mode security changes, or a restart. It is not transparent to the current sshx mount implementation and is not enabled yet: macFUSE requires the explicit `-o backend=fskit` option, FSKit only supports mount points below `/Volumes`, and several traditional mount options are unavailable. sshx currently creates private mounts below the runtime temporary directory and supplies VFS-oriented options. Supporting FSKit therefore requires a dedicated mount-path/options adapter, although the RemoteFS wire protocol and file-operation backend can remain unchanged.
|
|
123
|
+
|
|
124
|
+
The first version guarantees workspace-relative paths only. It does not rewrite absolute command arguments, add extra mount roots, expose special files/xattrs/ACLs, or support Docker targets, FUSE-T, or FSKit. It is optimized for source trees and small files rather than large-file throughput.
|
|
125
|
+
|
|
62
126
|
### 🔌 Automatic Port Detection & Forwarding
|
|
63
127
|
|
|
64
128
|
When a process on the remote starts listening on `127.0.0.1` or `0.0.0.0` (e.g., `npm run dev` on port 3000), sshx detects it and:
|
|
@@ -217,6 +281,10 @@ features:
|
|
|
217
281
|
# <host>.<user>.sshx:<remote-port>.
|
|
218
282
|
autoForward: true
|
|
219
283
|
|
|
284
|
+
# Read-write workspace mounts in both command directions. Default: false.
|
|
285
|
+
# Requires FUSE on the local machine and remote target.
|
|
286
|
+
remoteFs: false
|
|
287
|
+
|
|
220
288
|
commands:
|
|
221
289
|
# Commands blocked from bridge execution.
|
|
222
290
|
deny: []
|
|
@@ -241,7 +309,7 @@ commands:
|
|
|
241
309
|
```
|
|
242
310
|
|
|
243
311
|
1. **Connection**: `sshx remote` opens a normal SSH session and starts (or connects to) the client-target `sshx server` under `~/.sshx_server/<uuid>`.
|
|
244
|
-
2. **Bridge
|
|
312
|
+
2. **Bridge channels**: A hidden control `socket-proxy` channel links the client to the remote server. `remoteFs` adds a separately framed, bounded data channel paired by session ID.
|
|
245
313
|
3. **Port sniffing**: The server reads `/proc/net/tcp*` (Linux) to detect loopback (`127.0.0.1` / `::1`) and wildcard (`0.0.0.0` / `::`) listeners.
|
|
246
314
|
4. **Forwarding**: Detected ports are forwarded through a single shared local daemon using `ssh -W`.
|
|
247
315
|
5. **Domains**: The local DNS responder maps `<target>.<suffix>` → localhost. The browser's URL port selects the local forwarded port.
|
|
@@ -255,6 +323,8 @@ When `sshx` is invoked for a **non-matching host** (no sshx config, or host not
|
|
|
255
323
|
- `sshx --no-wrap ...` — skip all sshx behavior and call raw `ssh`.
|
|
256
324
|
- `SSHX_DISABLE=1 sshx ...` — same as `--no-wrap`, useful in scripts.
|
|
257
325
|
- `sshx local ...` on a **client** (not inside a remote session) — errors immediately with a clear message. `local` is globally reserved.
|
|
326
|
+
- `remoteFs` never silently falls back to an unmounted command. A failed FUSE mount fails the invocation.
|
|
327
|
+
- Workspace exports are anchored with Go's `os.Root`; path traversal and symlink escapes are rejected.
|
|
258
328
|
- Docker containers that aren't running or can't be reached are pure passthrough — sshx falls back to raw `ssh` with no side effects.
|
|
259
329
|
- Unmatched hosts are pure passthrough — no files created, no processes started.
|
|
260
330
|
|
|
@@ -271,6 +341,7 @@ When `sshx` is invoked for a **non-matching host** (no sshx config, or host not
|
|
|
271
341
|
- **Client**: macOS and Linux are fully supported.
|
|
272
342
|
- **Server**: Linux is required for the remote sshx server (uses `/proc/net/tcp*` for port detection).
|
|
273
343
|
- **Docker Client**: macOS and Linux — targets any running Docker container via `docker exec`.
|
|
344
|
+
- **remoteFs**: Linux is supported; macOS clients require macFUSE and are beta. Docker targets are not supported.
|
|
274
345
|
|
|
275
346
|
---
|
|
276
347
|
|
|
@@ -285,6 +356,7 @@ sshx/
|
|
|
285
356
|
│ ├── config/ # YAML configuration
|
|
286
357
|
│ ├── protocol/ # Client-server wire protocol
|
|
287
358
|
│ ├── bridge/ # Command bridge (remote → local execution)
|
|
359
|
+
│ ├── remotefs/ # FS protocol, secure backend, and FUSE adapter
|
|
288
360
|
│ ├── ports/ # Port sniffing (/proc/net/tcp*)
|
|
289
361
|
│ ├── forward/ # TCP forwarding
|
|
290
362
|
│ ├── domain/ # DNS resolver
|
|
@@ -300,7 +372,8 @@ sshx/
|
|
|
300
372
|
## Roadmap
|
|
301
373
|
|
|
302
374
|
- [x] **v1** — Command bridge (non-interactive), auto port forwarding, domain binding, shared server
|
|
303
|
-
- [ ] **v2** — Streaming stdin for command bridge,
|
|
375
|
+
- [ ] **v2** — Streaming stdin for command bridge, GitHub binary releases, Windows client support
|
|
376
|
+
- [x] **remoteFs beta** — Bidirectional read-write workspace mounting on Linux/macOS clients and Linux targets
|
|
304
377
|
|
|
305
378
|
---
|
|
306
379
|
|