vssh 4.3.0__tar.gz → 4.3.1__tar.gz
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.
- {vssh-4.3.0 → vssh-4.3.1}/CHANGELOG.md +45 -4
- vssh-4.3.1/CONTRIBUTING.md +44 -0
- vssh-4.3.1/HELP.md +127 -0
- vssh-4.3.1/PKG-INFO +322 -0
- vssh-4.3.1/README.ko.md +220 -0
- vssh-4.3.1/README.md +301 -0
- vssh-4.3.1/SECURITY.md +67 -0
- {vssh-4.3.0 → vssh-4.3.1}/cmd/vssh/main.go +7 -18
- {vssh-4.3.0 → vssh-4.3.1}/docs/DESIGN_RATIONALE_AND_DIRECTION.md +1 -1
- {vssh-4.3.0 → vssh-4.3.1}/docs/PUBLISH_HANDOFF.md +8 -2
- vssh-4.3.1/docs/PYTHON_SDK.md +93 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/SECURITY_TRANSPORT_MIGRATION.md +1 -1
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/auth.go +0 -35
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/server.go +7 -16
- vssh-4.3.1/internal/server/server_auth_test.go +37 -0
- vssh-4.3.1/internal/server/sync.go +113 -0
- vssh-4.3.1/internal/server/transfer_advanced.go +460 -0
- {vssh-4.3.0 → vssh-4.3.1}/scripts/authorize_fleet.sh +1 -1
- {vssh-4.3.0 → vssh-4.3.1}/scripts/build_node_registry.sh +1 -1
- {vssh-4.3.0 → vssh-4.3.1}/scripts/deploy_fleet.sh +1 -1
- {vssh-4.3.0 → vssh-4.3.1}/scripts/enable_require_tls.sh +1 -1
- {vssh-4.3.0 → vssh-4.3.1}/scripts/enroll.sh +5 -7
- {vssh-4.3.0 → vssh-4.3.1}/src/vssh/_version.py +2 -2
- vssh-4.3.0/CONTRIBUTING.md +0 -6
- vssh-4.3.0/HELP.md +0 -115
- vssh-4.3.0/PKG-INFO +0 -359
- vssh-4.3.0/README.ko.md +0 -326
- vssh-4.3.0/README.md +0 -338
- vssh-4.3.0/SECURITY.md +0 -16
- vssh-4.3.0/docs/DEV_STATUS_2026-06-12.md +0 -281
- vssh-4.3.0/docs/NEXT_SESSION_PROMPT.md +0 -60
- vssh-4.3.0/internal/server/auth_test.go +0 -57
- vssh-4.3.0/internal/server/sync.go +0 -228
- vssh-4.3.0/internal/server/transfer_advanced.go +0 -983
- {vssh-4.3.0 → vssh-4.3.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/.github/workflows/ci.yml +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/.github/workflows/release.yml +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/.gitignore +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/Makefile +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/cmd/vssh/doctor.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/cmd/vssh/fanout_test.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/cmd/vssh/mcp.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/cmd/vssh/mcp_test.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/cmd/vssh/setup.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/AGENT_READINESS_ROADMAP.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/AI_NATIVE_CAPABILITIES.ko.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/CODEX_ORCHESTRATION.ko.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/CODEX_ORCHESTRATION.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/DIRECTION.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/DISTRIBUTION.ko.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/GAP_ANALYSIS.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/NETWORK_TRAVERSAL_AUDIT.ko.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/PERFORMANCE.ko.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/PUBLISHING_AUDIT.ko.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/PUBLISHING_AUDIT.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/PYTHON_SDK.ko.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/ROADMAP.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/SECURITY_AUDIT_PACKAGE.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/SSH_REPLACEMENT_ROADMAP.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/WHY_VSSH.ko.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/docs/WHY_VSSH.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/go.mod +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/go.sum +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/install.sh +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/adapter/vssh.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/agent/agent.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/agent/api.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/config/config.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/event/event.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/artifact_test.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/client.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/exec_test.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/fmux.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/forward.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/identity.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/jobs.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/jobs_test.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/policy.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/policy_e2e_test.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/policy_templates_test.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/policy_test.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/pty_darwin.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/pty_linux.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/relay.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/rpc.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/tlsident.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/transfer.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/server/transfer_test.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/ssh/ssh.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/internal/ssh/ssh_test.go +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/policies/README.md +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/policies/backup.json +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/policies/ci.json +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/policies/deploy.json +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/policies/readonly.json +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/pyproject.toml +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/scripts/audit_transport_scan.sh +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/scripts/cross_authorize_fleet.sh +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/scripts/pin_fleet_keys.sh +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/src/vssh/__init__.py +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/src/vssh/__main__.py +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/src/vssh/_bootstrap.py +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/src/vssh/_cli.py +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/src/vssh/client.py +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/test/agent_suite.sh +0 -0
- {vssh-4.3.0 → vssh-4.3.1}/tests/test_python_sdk.py +0 -0
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
- Docs (README/HELP/SECURITY + ko) updated to the key-only model (no shared
|
|
6
|
+
secret in quickstart, auth via `~/.vssh/authorized_keys`). pip `vssh` 4.3.1
|
|
7
|
+
fetches the 0.7.38 binary.
|
|
8
|
+
|
|
9
|
+
### Security/cleanup (2026-06-14) — P4 finish: secret-free daemon, dead HMAC code removed (v0.7.38)
|
|
10
|
+
|
|
11
|
+
- `vssh server` no longer requires (or reads) a shared secret to start — auth is
|
|
12
|
+
purely per-node Ed25519 keys. Removed the secret-required startup gate and the
|
|
13
|
+
`VSSH_INSECURE_ALLOW_EMPTY_SECRET` escape hatch from `cmd/vssh`.
|
|
14
|
+
- Deleted the now-dead HMAC code: `server.ValidateAuthToken`,
|
|
15
|
+
`server.GenerateAuthToken`, the legacy HMAC-authenticated client transfer
|
|
16
|
+
functions (`SendFileCompressed/SendFileResume/ParallelDownload/PipeUp/PipeDown/
|
|
17
|
+
MultiPut/SyncFile` + helpers), and the HMAC token unit tests. The modern
|
|
18
|
+
`dialAuth`/`Handle*` (VAUTH1) paths are unaffected.
|
|
19
|
+
- `scripts/enroll.sh` is now key-only: it installs the daemon unit WITHOUT
|
|
20
|
+
`VSSH_SECRET` and verifies via VAUTH1 (no shared secret anywhere in onboarding).
|
|
21
|
+
- `go vet`/`go test` green (incl. `TestServerRejectsLegacyHMACAuth`).
|
|
22
|
+
|
|
23
|
+
### Security (2026-06-14) — P4: key-only auth (legacy shared-secret HMAC removed)
|
|
24
|
+
|
|
25
|
+
- The daemon now accepts **only per-node Ed25519 VAUTH1**. The legacy shared-secret
|
|
26
|
+
(HMAC) authentication path was removed from `internal/server/server.go`: any
|
|
27
|
+
non-VAUTH1 auth line — including a *valid* HMAC token for the configured secret —
|
|
28
|
+
is rejected (`AUTH_FAILED`). This removes the entire class of risk where one
|
|
29
|
+
fleet-wide shared secret, if leaked, grants access, and eliminates the secret
|
|
30
|
+
that could be hardcoded or re-leaked.
|
|
31
|
+
- `dialAuth` (the canonical client path) has been VAUTH1-only since 0.7.25; the
|
|
32
|
+
remaining `GenerateAuthToken` callers (`transfer_advanced.go` / `sync.go`) are
|
|
33
|
+
legacy client functions not wired to any CLI command. The HMAC helpers remain
|
|
34
|
+
for now but are unreachable by the daemon.
|
|
35
|
+
- New regression test `TestServerRejectsLegacyHMACAuth`; `go vet`/`go test` green.
|
|
36
|
+
- Operational: the live fleet already enforces VAUTH at runtime
|
|
37
|
+
(`VSSH_REQUIRE_VAUTH=1`, incl. the m1 controller as of 2026-06-14); this makes
|
|
38
|
+
key-only the built-in default. Rollout (build → d1 canary → deploy_fleet → drop
|
|
39
|
+
`VSSH_SECRET` from units + retire legacy HMAC helpers) is deferred until all
|
|
40
|
+
nodes are reachable. **Not yet deployed.**
|
|
41
|
+
|
|
5
42
|
### Distribution (2026-06-14) — P1 one-line install pipeline (v0.7.36)
|
|
6
43
|
|
|
7
44
|
- **Makefile version single-sourced** from `cmd/vssh/main.go` (was hardcoded
|
|
@@ -15,14 +52,18 @@
|
|
|
15
52
|
console-script that downloads the matching Go release binary to `~/.vssh/bin`
|
|
16
53
|
on first use (stdlib-only, checksum-verified, `VSSH_BIN`/`VSSH_VERSION`/`VSSH_HOME`
|
|
17
54
|
overrides, atomic cache write) AND keeps `from vssh import VSSH` importable.
|
|
18
|
-
Package version
|
|
55
|
+
Package version (`src/vssh/_version.py:__version__`) stays on PyPI's existing
|
|
56
|
+
`vssh` 4.x line (4.3.0) so `pip install vssh` resolves to it (highest wins); the
|
|
57
|
+
launcher downloads the decoupled `BINARY_VERSION` (0.7.36) GitHub release asset.
|
|
19
58
|
`python -m vssh` works.
|
|
20
59
|
- Verified on m1: `go vet`/`go test` green, Python SDK 8/8, `make release`
|
|
21
60
|
4-arch + checksums, wheel/sdist build, fresh-venv install (SDK import +
|
|
22
61
|
console-script exec), and an adversarial download test (happy path +
|
|
23
62
|
tampered-checksum rejection fail-closed + `VSSH_BIN` override).
|
|
24
|
-
-
|
|
25
|
-
|
|
63
|
+
- PUBLISHED 2026-06-14: pushed `main` + tag `v0.7.36`; GitHub release (CI-built
|
|
64
|
+
4 binaries + `checksums.txt`, marked Latest); PyPI `vssh` **4.3.0**. Verified
|
|
65
|
+
live on m1: one-line `install.sh` (checksum-verified -> `vssh 0.7.36`) and
|
|
66
|
+
`pip install vssh` -> import SDK + `vssh --version` downloads 0.7.36 binary.
|
|
26
67
|
|
|
27
68
|
### Tooling (2026-06-13) — P1a one-command node onboarding
|
|
28
69
|
|
|
@@ -314,7 +355,7 @@ new-TLS); fleet `agent_suite` 38/38 GREEN over the new TLS client across
|
|
|
314
355
|
`d1 g1 c1 v1 macmini` (linux + darwin); `handshake-test --tls` AUTH_OK against
|
|
315
356
|
both a 0.7.26 (d1) and a 0.7.25 (c1) daemon; rolled out to 14 online nodes
|
|
316
357
|
(`deploy_fleet.sh`), `n1 s1 s2` offline/skipped. m1 coordinator binary was on 0.7.25 during rollout, then upgraded to 0.7.26 the
|
|
317
|
-
same day via the safe bootout/bootstrap procedure (
|
|
358
|
+
same day via the safe bootout/bootstrap procedure (internal release note).
|
|
318
359
|
|
|
319
360
|
## [v0.7.25] - 2026-06-13
|
|
320
361
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping improve `vssh`. This is a Go binary with a small Python SDK.
|
|
4
|
+
|
|
5
|
+
## Development setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/meshpop/vssh && cd vssh
|
|
9
|
+
make build # build ./vssh
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Requires Go 1.25+ (and Python 3.9+ for the SDK tests).
|
|
13
|
+
|
|
14
|
+
## Before opening a PR
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
go vet ./...
|
|
18
|
+
go build ./...
|
|
19
|
+
go test ./... # Go tests
|
|
20
|
+
make test # Go tests + Python SDK tests
|
|
21
|
+
bash -n install.sh # when editing the installer
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
CI runs the same checks. Please make sure they pass locally.
|
|
25
|
+
|
|
26
|
+
## Pull requests
|
|
27
|
+
|
|
28
|
+
- Target `main`.
|
|
29
|
+
- Keep changes focused and describe behavior changes clearly — **especially
|
|
30
|
+
anything touching authentication, transport, policy, or `vssh server`.**
|
|
31
|
+
- Update `CHANGELOG.md` and bump the version in `cmd/vssh/main.go` for
|
|
32
|
+
user-visible changes.
|
|
33
|
+
- Add or update tests for new behavior.
|
|
34
|
+
|
|
35
|
+
## Releasing
|
|
36
|
+
|
|
37
|
+
Maintainers: see [docs/PUBLISH_HANDOFF.md](docs/PUBLISH_HANDOFF.md) for the
|
|
38
|
+
release process (tag → CI builds the GitHub release → PyPI upload).
|
|
39
|
+
|
|
40
|
+
## Security
|
|
41
|
+
|
|
42
|
+
Report vulnerabilities privately via
|
|
43
|
+
[GitHub Security Advisories](https://github.com/meshpop/vssh/security/advisories/new),
|
|
44
|
+
not public issues or PRs.
|
vssh-4.3.1/HELP.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# vssh — help & usage
|
|
2
|
+
|
|
3
|
+
`vssh` is an sshd-free, AI-native remote execution daemon for private networks.
|
|
4
|
+
It runs commands, transfers files, and manages jobs on remote nodes over TLS 1.3
|
|
5
|
+
with Ed25519 key authentication, returning structured execution evidence.
|
|
6
|
+
|
|
7
|
+
- No `sshd` required on the target
|
|
8
|
+
- Built-in PTY, typed RPC, file transfer, and long-running jobs
|
|
9
|
+
- TLS 1.3 + Ed25519 key auth (legacy shared-secret path for bootstrap)
|
|
10
|
+
- Node-name routing over Tailscale, Wire/WireGuard, LAN, or configured addresses
|
|
11
|
+
- A built-in MCP server (`vssh mcp`) for AI agents
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
curl -fsSL https://raw.githubusercontent.com/meshpop/vssh/main/install.sh | bash
|
|
17
|
+
# or
|
|
18
|
+
pip install vssh
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# On the target node (no shared secret — key-authenticated)
|
|
25
|
+
vssh server # listens on :48291
|
|
26
|
+
|
|
27
|
+
# On the client: print your key, add it to the server's ~/.vssh/authorized_keys
|
|
28
|
+
vssh pubkey
|
|
29
|
+
vssh run web1 "uptime" # structured result
|
|
30
|
+
vssh web1 # interactive shell
|
|
31
|
+
vssh doctor --json # diagnose before AI/MCP use
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Command reference
|
|
35
|
+
|
|
36
|
+
### Execution
|
|
37
|
+
```bash
|
|
38
|
+
vssh <node> # interactive PTY shell
|
|
39
|
+
vssh shell <node> # interactive PTY shell
|
|
40
|
+
vssh run <node> <command> # run a command (structured result)
|
|
41
|
+
vssh exec <node> <command> # alias for run
|
|
42
|
+
vssh run-many <n1,n2> <cmd> # run across comma-separated nodes
|
|
43
|
+
vssh run-batch <node> ... # run several commands on one session
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Typed APIs
|
|
47
|
+
```bash
|
|
48
|
+
vssh rpc <node> <method> [json] # call a typed daemon RPC
|
|
49
|
+
vssh rpc-many <nodes> <method> [json] # RPC across nodes
|
|
50
|
+
vssh facts <node> # typed host facts
|
|
51
|
+
vssh facts-many <nodes> # facts across nodes
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Jobs (long-running)
|
|
55
|
+
```bash
|
|
56
|
+
vssh job-start <node> <command> # start a background job
|
|
57
|
+
vssh job-status <node> <id> # job status
|
|
58
|
+
vssh job-logs <node> <id> # job logs
|
|
59
|
+
vssh job-cancel <node> <id> # cancel a job
|
|
60
|
+
vssh artifact-collect <node> # collect output artifacts
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Files
|
|
64
|
+
```bash
|
|
65
|
+
vssh put <local> <node:path> # upload
|
|
66
|
+
vssh get <node:path> <local> # download
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Fleet & ops
|
|
70
|
+
```bash
|
|
71
|
+
vssh # dashboard (default)
|
|
72
|
+
vssh status # dashboard
|
|
73
|
+
vssh list # list known nodes
|
|
74
|
+
vssh doctor [--json] # diagnose binary, secret, config, peers, MCP readiness
|
|
75
|
+
vssh deploy <node> # atomic binary install + restart + verify
|
|
76
|
+
vssh server # run the daemon
|
|
77
|
+
vssh mcp # run the MCP server (for AI agents)
|
|
78
|
+
vssh setup # first-run self-configuration
|
|
79
|
+
vssh version # show version
|
|
80
|
+
vssh help # full help
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Discovery
|
|
84
|
+
|
|
85
|
+
`vssh` finds nodes from, in order: a Wire coordinator, Tailscale, the config
|
|
86
|
+
file (`~/.vssh/servers.json`), and a local cache. You can always address a node
|
|
87
|
+
by an explicit IP as well.
|
|
88
|
+
|
|
89
|
+
## Configuration
|
|
90
|
+
|
|
91
|
+
### Node inventory — `~/.vssh/servers.json`
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"web1": { "ip": "192.0.2.10", "user": "deploy" },
|
|
95
|
+
"db1": { "ip": "192.0.2.20", "user": "postgres" }
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Per-host users — `~/.wire/users.json` (root: `/etc/wire/users.json`)
|
|
100
|
+
```json
|
|
101
|
+
{ "web1": "deploy", "db1": "postgres" }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
> Keep real inventory, hostnames, VPN IPs, and secrets **out of source control**.
|
|
105
|
+
|
|
106
|
+
## Environment variables
|
|
107
|
+
|
|
108
|
+
| Variable | Description |
|
|
109
|
+
|----------|-------------|
|
|
110
|
+
| `VSSH_PORT` | Daemon listen port (default **48291**). |
|
|
111
|
+
| `VSSH_REQUIRE_TLS` | `1` = refuse non-TLS connections. |
|
|
112
|
+
| `VSSH_NO_HOSTKEY_VERIFY` | `1` = opt out of host-identity verification (not recommended). |
|
|
113
|
+
| `VSSH_BIN` / `VSSH_VERSION` / `VSSH_HOME` | pip-wrapper/installer overrides (see README). |
|
|
114
|
+
|
|
115
|
+
## Security
|
|
116
|
+
|
|
117
|
+
`vssh server` authenticates peers with **TLS 1.3 + Ed25519 keys (VAUTH1)** only —
|
|
118
|
+
no shared secret. Authorize clients via `~/.vssh/authorized_keys`. Commands can be
|
|
119
|
+
gated with optional per-key policy. The VPN encrypts the tunnel but does **not**
|
|
120
|
+
replace vssh authentication. Full details and
|
|
121
|
+
a hardening checklist: [SECURITY.md](SECURITY.md).
|
|
122
|
+
|
|
123
|
+
## More
|
|
124
|
+
|
|
125
|
+
- MCP / agent orchestration: [docs/CODEX_ORCHESTRATION.md](docs/CODEX_ORCHESTRATION.md)
|
|
126
|
+
- Python SDK: [docs/PYTHON_SDK.md](docs/PYTHON_SDK.md)
|
|
127
|
+
- Why vssh: [docs/WHY_VSSH.md](docs/WHY_VSSH.md)
|
vssh-4.3.1/PKG-INFO
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vssh
|
|
3
|
+
Version: 4.3.1
|
|
4
|
+
Summary: vssh — AI-native, drop-in ssh replacement (CLI binary + Python SDK)
|
|
5
|
+
Project-URL: Homepage, https://github.com/meshpop/vssh
|
|
6
|
+
Project-URL: Repository, https://github.com/meshpop/vssh
|
|
7
|
+
Author: MeshPop
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: ai-agents,mcp,remote-execution,ssh,tailscale,vssh
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: System :: Systems Administration
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# vssh
|
|
23
|
+
|
|
24
|
+
**An sshd-free, AI-native remote execution daemon for private networks.**
|
|
25
|
+
|
|
26
|
+
`vssh` runs commands, transfers files, and manages long-running jobs on remote
|
|
27
|
+
nodes over your private network (Tailscale, WireGuard/Wire, or LAN) — without
|
|
28
|
+
running `sshd` on the target. It speaks a typed protocol over TLS 1.3 with
|
|
29
|
+
Ed25519 key authentication, and every result comes back as structured evidence
|
|
30
|
+
(stdout, stderr, exit code, duration, transport), which makes it a natural
|
|
31
|
+
execution layer for AI agents and automation as well as for humans.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Install (Linux/macOS, amd64/arm64)
|
|
35
|
+
curl -fsSL https://raw.githubusercontent.com/meshpop/vssh/main/install.sh | bash
|
|
36
|
+
# or
|
|
37
|
+
pip install vssh
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Why vssh
|
|
43
|
+
|
|
44
|
+
Use `vssh` when the operator is often an **AI agent or automation runtime**, not
|
|
45
|
+
a person typing into a terminal, and when you want execution that is:
|
|
46
|
+
|
|
47
|
+
- **sshd-free** — the target runs `vssh server`, not OpenSSH.
|
|
48
|
+
- **typed & auditable** — structured `stdout/stderr/exit/duration` evidence, not a raw text stream.
|
|
49
|
+
- **policy-gated** — classify and block dangerous commands before they run.
|
|
50
|
+
- **durable** — start/poll/cancel long-running jobs and collect artifacts.
|
|
51
|
+
- **name-routed** — address nodes by name and capability, not raw IPs.
|
|
52
|
+
|
|
53
|
+
If all you need is an interactive human shell on a box that already runs `sshd`,
|
|
54
|
+
use `ssh` directly — `vssh` deliberately does not wrap OpenSSH. See
|
|
55
|
+
[docs/WHY_VSSH.md](docs/WHY_VSSH.md).
|
|
56
|
+
|
|
57
|
+
**Out of scope:** operating the VPN mesh and fleet dashboards. Use
|
|
58
|
+
[Wire](https://github.com/meshpop/wire) for the network layer and
|
|
59
|
+
[mpop](https://github.com/meshpop/mpop) for monitoring.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
### One-line installer (recommended)
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
curl -fsSL https://raw.githubusercontent.com/meshpop/vssh/main/install.sh | bash
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The installer detects your OS/arch, downloads the matching binary from the
|
|
72
|
+
[latest GitHub release](https://github.com/meshpop/vssh/releases/latest),
|
|
73
|
+
**verifies its SHA-256 against the published `checksums.txt`**, and installs to
|
|
74
|
+
`~/bin`. Options:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Install a specific version
|
|
78
|
+
curl -fsSL .../install.sh | VSSH_VERSION=0.7.36 bash
|
|
79
|
+
# Install to a custom directory
|
|
80
|
+
curl -fsSL .../install.sh | INSTALL_DIR=/usr/local/bin bash
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### pip (CLI + Python SDK)
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pip install vssh
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
This installs both the `vssh` CLI (the Go binary is fetched and checksum-verified
|
|
90
|
+
for your platform on first run, cached under `~/.vssh/bin`) **and** the Python
|
|
91
|
+
SDK (`from vssh import VSSH`). See [Python SDK](#python-sdk).
|
|
92
|
+
|
|
93
|
+
### From source
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
git clone https://github.com/meshpop/vssh && cd vssh
|
|
97
|
+
make build # builds ./vssh
|
|
98
|
+
make install # installs to /usr/local/bin (sudo)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Requires Go 1.25+.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Quick start
|
|
106
|
+
|
|
107
|
+
On the **target** node, start the daemon (no shared secret — auth is key-based):
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
vssh server # listens on :48291
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Authorize a client by adding its public key to the server's
|
|
114
|
+
`~/.vssh/authorized_keys` (run `vssh pubkey` on the client to print it). For a
|
|
115
|
+
fleet, `scripts/enroll.sh <node>` does this from a controller automatically.
|
|
116
|
+
Then, from the client:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
vssh run web1 "df -h" # run a command, get structured output
|
|
120
|
+
vssh web1 # open an interactive shell
|
|
121
|
+
vssh put ./app web1:/tmp/ # upload a file
|
|
122
|
+
vssh get web1:/var/log/x . # download a file
|
|
123
|
+
vssh # fleet dashboard
|
|
124
|
+
vssh doctor --json # diagnose binary, secret, config, peers, MCP
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`vssh run` returns an evidence envelope — exit code, durations, transport, and
|
|
128
|
+
the endpoints it tried — not just raw text.
|
|
129
|
+
|
|
130
|
+
> For a multi-node fleet, `scripts/enroll.sh <node>` installs the daemon and
|
|
131
|
+
> cross-authorizes keys from a controller. See [Security](#security).
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## How it works
|
|
136
|
+
|
|
137
|
+
```text
|
|
138
|
+
vssh client ──TLS 1.3──▶ vssh server ──▶ typed exec / file / job / RPC APIs ──▶ structured evidence
|
|
139
|
+
(Ed25519 pinned) (:48291)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
1. **Transport** — TLS 1.3 with the daemon's **Ed25519 public key pinned**
|
|
143
|
+
(raw-key, not a CA). The client is TLS-first; set `VSSH_REQUIRE_TLS=1` to
|
|
144
|
+
refuse plaintext entirely.
|
|
145
|
+
2. **Host identity** — the client verifies it reached the *intended* host by
|
|
146
|
+
checking the daemon key against a trusted registry (on by default since
|
|
147
|
+
0.7.33), so a name can't be silently misrouted to the wrong machine.
|
|
148
|
+
3. **Authentication** — per-node **Ed25519 challenge–response (VAUTH1)** only.
|
|
149
|
+
There is no shared secret; a client is authorized by listing its public key in
|
|
150
|
+
the server's `~/.vssh/authorized_keys` (or `/etc/vssh/authorized_keys`).
|
|
151
|
+
4. **Policy** — commands can be classified and gated before execution; per-key
|
|
152
|
+
allow/deny lists, path scoping, and rate limits are available opt-in.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## CLI reference
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
Execution
|
|
160
|
+
vssh <node> Interactive PTY shell
|
|
161
|
+
vssh shell <node> Interactive PTY shell
|
|
162
|
+
vssh run <node> <cmd> Run a command (structured result)
|
|
163
|
+
vssh exec <node> <cmd> Alias for run
|
|
164
|
+
vssh run-many <n1,n2> <cmd> Run across comma-separated nodes
|
|
165
|
+
vssh run-batch <node> ... Run multiple commands on one session
|
|
166
|
+
|
|
167
|
+
Typed APIs
|
|
168
|
+
vssh rpc <node> <method> [json] Call a typed daemon RPC
|
|
169
|
+
vssh rpc-many <nodes> <method> [json] RPC across nodes
|
|
170
|
+
vssh facts <node> Typed host facts
|
|
171
|
+
vssh facts-many <nodes> Facts across nodes
|
|
172
|
+
|
|
173
|
+
Jobs (long-running)
|
|
174
|
+
vssh job-start <node> <cmd> Start a background job
|
|
175
|
+
vssh job-status <node> <id> Job status
|
|
176
|
+
vssh job-logs <node> <id> Job logs
|
|
177
|
+
vssh job-cancel <node> <id> Cancel a job
|
|
178
|
+
vssh artifact-collect <node> Collect output artifacts
|
|
179
|
+
|
|
180
|
+
Files
|
|
181
|
+
vssh put <local> <node:path> Upload
|
|
182
|
+
vssh get <node:path> <local> Download
|
|
183
|
+
|
|
184
|
+
Fleet & ops
|
|
185
|
+
vssh Dashboard (default)
|
|
186
|
+
vssh status Dashboard
|
|
187
|
+
vssh list List known nodes
|
|
188
|
+
vssh doctor [--json] Diagnose local setup
|
|
189
|
+
vssh deploy <node> Atomic binary install + restart + verify
|
|
190
|
+
vssh server Run the daemon
|
|
191
|
+
vssh mcp Run the MCP server (for AI agents)
|
|
192
|
+
vssh setup First-run self-configuration
|
|
193
|
+
vssh version Show version
|
|
194
|
+
vssh help Full help
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## MCP server (for AI agents)
|
|
200
|
+
|
|
201
|
+
The MCP server is built into the binary — no separate install:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
vssh mcp
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
It exposes typed tools that return execution evidence, so an agent can route,
|
|
208
|
+
gate, and run work with an audit trail:
|
|
209
|
+
|
|
210
|
+
| Tool | Purpose |
|
|
211
|
+
|------|---------|
|
|
212
|
+
| `vssh_doctor` | Diagnose binary, secret source, config, peers, MCP readiness |
|
|
213
|
+
| `vssh_hosts_list` | List known hosts (addresses, tags, capabilities, health) for routing |
|
|
214
|
+
| `vssh_route_select` | Pick the best host by capability, tag, and health |
|
|
215
|
+
| `vssh_exec_safe` | Run read-only/diagnostic commands (dangerous ones blocked) |
|
|
216
|
+
| `vssh_exec` | Run with policy checks; `allow_dangerous` after explicit approval |
|
|
217
|
+
| `vssh_exec_routed` | Route first, then execute with policy + evidence |
|
|
218
|
+
| `vssh_policy_check` | Classify a command before running it |
|
|
219
|
+
| `vssh_status`, `vssh_list` | Status and peer inventory |
|
|
220
|
+
|
|
221
|
+
Commands matching destructive patterns (`rm -rf`, `shutdown`, `reboot`,
|
|
222
|
+
`docker rm`, `kubectl delete`, `systemctl restart`, …) are **blocked** unless the
|
|
223
|
+
caller sets `allow_dangerous: true` after explicit human approval. Every response
|
|
224
|
+
is an evidence envelope with timestamps, the policy decision, target, command,
|
|
225
|
+
and the structured result. See [docs/CODEX_ORCHESTRATION.md](docs/CODEX_ORCHESTRATION.md).
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Python SDK
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
from vssh import VSSH
|
|
233
|
+
|
|
234
|
+
client = VSSH(secret="a-long-random-value")
|
|
235
|
+
|
|
236
|
+
client.exec("web1", "uptime") # -> ExecResult(stdout, exit_code, ...)
|
|
237
|
+
client.exec_many(["web1", "db1"], "uptime")
|
|
238
|
+
client.facts("web1") # typed host facts
|
|
239
|
+
job = client.job_start("web1", "long-task")
|
|
240
|
+
client.job_status("web1", job["job_id"])
|
|
241
|
+
client.doctor()
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
The SDK is a thin client over the installed `vssh` binary (it does not
|
|
245
|
+
reimplement the protocol), so it inherits the same transport, auth, and policy.
|
|
246
|
+
Full method list: `exec`, `exec_many`, `rpc`, `rpc_many`, `facts`, `facts_many`,
|
|
247
|
+
`job_start`, `job_status`, `job_logs`, `job_cancel`, `artifact_collect`,
|
|
248
|
+
`doctor`. See [docs/PYTHON_SDK.md](docs/PYTHON_SDK.md).
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Configuration
|
|
253
|
+
|
|
254
|
+
### Node inventory — `~/.vssh/servers.json`
|
|
255
|
+
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"web1": { "ip": "192.0.2.10", "user": "deploy", "tags": ["linux", "web"], "capabilities": ["docker"] },
|
|
259
|
+
"gpu1": { "ip": "192.0.2.20", "user": "ubuntu", "tags": ["gpu"], "capabilities": ["cuda", "ollama"], "monitor_port": 8721 }
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Nodes are also discovered automatically from a Wire coordinator, Tailscale, and a
|
|
264
|
+
local cache. **Do not commit a real `servers.json`, hostnames, VPN IPs, or
|
|
265
|
+
secrets** — keep inventory outside the repo and use example values in docs.
|
|
266
|
+
|
|
267
|
+
### Per-host users — `~/.wire/users.json`
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{ "web1": "deploy", "db1": "postgres" }
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Environment variables
|
|
274
|
+
|
|
275
|
+
| Variable | Purpose |
|
|
276
|
+
|----------|---------|
|
|
277
|
+
| `VSSH_PORT` | Daemon listen port (default **48291**). |
|
|
278
|
+
| `VSSH_REQUIRE_TLS` | `1` = refuse non-TLS connections. |
|
|
279
|
+
| `VSSH_NO_HOSTKEY_VERIFY` | `1` = opt out of host-identity verification (not recommended). |
|
|
280
|
+
| `VSSH_BIN` | (pip wrapper) use this binary instead of downloading. |
|
|
281
|
+
| `VSSH_VERSION` | (pip wrapper / installer) pin the binary release to fetch. |
|
|
282
|
+
| `VSSH_HOME` | Override the `~/.vssh` directory. |
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Security
|
|
287
|
+
|
|
288
|
+
- The native daemon grants authorized peers command execution and file transfer
|
|
289
|
+
**as the configured user** — treat access as root-equivalent.
|
|
290
|
+
- Authentication is **per-node Ed25519 keys (VAUTH1)** only; authorize clients via
|
|
291
|
+
`~/.vssh/authorized_keys`. Enforce encryption with `VSSH_REQUIRE_TLS=1`.
|
|
292
|
+
- The VPN (WireGuard/Tailscale) encrypts the tunnel but is **not** a substitute
|
|
293
|
+
for vssh authentication — always set a strong secret or enroll keys, and
|
|
294
|
+
firewall the listen port.
|
|
295
|
+
- Report vulnerabilities privately via
|
|
296
|
+
[GitHub Security Advisories](https://github.com/meshpop/vssh/security/advisories/new).
|
|
297
|
+
|
|
298
|
+
Full model and hardening steps: [SECURITY.md](SECURITY.md).
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Documentation
|
|
303
|
+
|
|
304
|
+
- [Why vssh](docs/WHY_VSSH.md) — positioning and scope
|
|
305
|
+
- [Python SDK](docs/PYTHON_SDK.md) — SDK reference
|
|
306
|
+
- [Codex / agent orchestration](docs/CODEX_ORCHESTRATION.md) — MCP usage for agents
|
|
307
|
+
- [SECURITY.md](SECURITY.md) · [CONTRIBUTING.md](CONTRIBUTING.md) · [CHANGELOG.md](CHANGELOG.md)
|
|
308
|
+
- [한국어 README](README.ko.md)
|
|
309
|
+
|
|
310
|
+
## Building & contributing
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
make build # build ./vssh
|
|
314
|
+
make test # go test ./... + Python SDK tests
|
|
315
|
+
make release # cross-compile linux/darwin × amd64/arm64 into dist/
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
319
|
+
|
|
320
|
+
## License
|
|
321
|
+
|
|
322
|
+
MIT
|