nullgate 1.2.2__tar.gz → 1.2.5__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.
- {nullgate-1.2.2/src/nullgate.egg-info → nullgate-1.2.5}/PKG-INFO +78 -15
- {nullgate-1.2.2 → nullgate-1.2.5}/README.md +77 -14
- nullgate-1.2.5/src/nullgate/__init__.py +1 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate/commands.py +56 -4
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate/session.py +282 -29
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate/transports.py +48 -22
- {nullgate-1.2.2 → nullgate-1.2.5/src/nullgate.egg-info}/PKG-INFO +78 -15
- nullgate-1.2.5/tests/test_commands.py +2169 -0
- nullgate-1.2.2/src/nullgate/__init__.py +0 -1
- nullgate-1.2.2/tests/test_commands.py +0 -731
- {nullgate-1.2.2 → nullgate-1.2.5}/LICENSE +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/pyproject.toml +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/setup.cfg +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate/account.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate/bridge.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate/client_config.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate/gateway.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate/ingress.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate/runtime.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate/wsroute.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate.egg-info/SOURCES.txt +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate.egg-info/dependency_links.txt +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate.egg-info/entry_points.txt +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate.egg-info/requires.txt +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/src/nullgate.egg-info/top_level.txt +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/tests/test_account.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/tests/test_bridge.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/tests/test_gateway.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/tests/test_ingress.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/tests/test_install.py +0 -0
- {nullgate-1.2.2 → nullgate-1.2.5}/tests/test_wsroute.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nullgate
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.5
|
|
4
4
|
Summary: Disposable SSH gateway into confined directory workspaces
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -19,7 +19,7 @@ Disposable SSH gateway into confined directory workspaces for remote containers,
|
|
|
19
19
|
Run Nullgate directly from PyPI without installing it first:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
# Share the current directory over the default
|
|
22
|
+
# Share the current directory over the default srv.us provider
|
|
23
23
|
uvx nullgate start
|
|
24
24
|
|
|
25
25
|
# Share a specific workspace
|
|
@@ -36,13 +36,13 @@ uvx nullgate status
|
|
|
36
36
|
uvx nullgate connect
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Nullgate
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
Nullgate requires authentication by default (an authorized SSH key and/or a
|
|
40
|
+
generated password). Pass `--public-access` to allow connections without
|
|
41
|
+
credentials (unsafe on public endpoints).
|
|
42
42
|
|
|
43
43
|
## Features
|
|
44
44
|
|
|
45
|
-
- **Ingress Transports**: Publish endpoints via
|
|
45
|
+
- **Ingress Transports**: Publish endpoints via srv.us reverse tunnels (default), Upterm WebSocket relays, Cloudflare Worker relays, or Cloudflare Argo (`cloudflared`) tunnels.
|
|
46
46
|
- **Confinement**: SFTP and SCP workloads are restricted to the designated workspace root; parent traversals and out-of-root symlinks are blocked.
|
|
47
47
|
- **Host file visibility**: Relative transfer paths begin in the workspace root while absolute paths address host locations, matching shell behavior; add `--restrict-file-transfer` for strict workspace-only transfers.
|
|
48
48
|
- **Direct Shell Access**: Authenticated PTY sessions run interactively under the local user credentials.
|
|
@@ -72,10 +72,12 @@ pip install nullgate
|
|
|
72
72
|
|
|
73
73
|
### Start
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
Start the gateway service and ingress transport, then report readiness once the
|
|
76
|
+
gateway listens, the transport stays alive, and srv.us has announced a
|
|
77
|
+
hostname (for that provider):
|
|
76
78
|
|
|
77
79
|
```bash
|
|
78
|
-
# Default
|
|
80
|
+
# Default srv.us transport on port 4822 sharing current directory
|
|
79
81
|
nullgate start
|
|
80
82
|
|
|
81
83
|
# Custom path, port, and slot
|
|
@@ -94,16 +96,26 @@ nullgate start . --provider cloudflared --public-hostname workspace.example.com
|
|
|
94
96
|
Options:
|
|
95
97
|
- `-p`, `--ssh-port`: Local SSH server port.
|
|
96
98
|
- `-s`, `--tunnel-slot`: srv.us tunnel slot.
|
|
97
|
-
- `-t`, `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `
|
|
99
|
+
- `-t`, `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `srvus`.
|
|
98
100
|
- `-e`, `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
|
|
99
101
|
- `-H`, `--public-hostname`: Public hostname used with `cloudflared`.
|
|
100
102
|
- `--cloudflare-token`: Cloudflare tunnel credential, or set `NULLGATE_CLOUDFLARED_TOKEN`.
|
|
101
|
-
- `--
|
|
103
|
+
- `--identity-seed VALUE`: srv.us identity seed value (visible in argv and shell history; flag overrides seed file and `NULLGATE_IDENTITY_SEED`; other providers ignore it). Prefer `--identity-seed-file PATH` to avoid history exposure. The direct value is never printed or saved; `restart` cannot reuse it because only the seed-file path is persisted. The seed only matters when the identity key does not yet exist.
|
|
104
|
+
- `--identity-seed-file PATH`: Read the srv.us identity seed from a file (overrides `NULLGATE_IDENTITY_SEED`; other providers ignore it). The file must hold nonempty UTF-8 text; only the path is saved for `restart`, never the seed value. `restart` revalidates the saved file before stopping the running session. The seed only matters when the identity key does not yet exist.
|
|
105
|
+
- `--public-access`: Allow connections without credentials (unsafe on public endpoints). Off by default; only `restart` reuses a saved setting, a fresh `start` always defaults to authenticated access.
|
|
102
106
|
- `--no-public-access`: Require authentication.
|
|
103
|
-
- `--tcp-forwarding`:
|
|
104
|
-
- `--no-tcp-forwarding`: Disable SSH TCP tunneling.
|
|
107
|
+
- `--tcp-forwarding`: Allow SSH TCP tunneling (`ssh -L`; enabled by default on fresh `start`).
|
|
108
|
+
- `--no-tcp-forwarding`: Disable SSH TCP tunneling. `restart` reuses the saved effective setting.
|
|
105
109
|
- `--restrict-file-transfer`: Keep SFTP and SCP inside the workspace.
|
|
106
110
|
- `--no-restrict-file-transfer`: Allow host-visible file transfers.
|
|
111
|
+
- `--foreground`: Stay in the foreground and supervise gateway and transport instead of exiting after readiness. The parent handles SIGINT and SIGTERM and stops both children, exiting nonzero with recent log tails if either child dies.
|
|
112
|
+
- `--json`: Emit machine-readable JSON on stdout (the only stdout in JSON mode). `start --foreground --json` prints one readiness object, flushes it, then supervises.
|
|
113
|
+
|
|
114
|
+
A fresh `start` uses documented defaults and the current directory when no
|
|
115
|
+
workspace is given; only `restart` reuses saved workspace, provider, port,
|
|
116
|
+
and security settings. Only the hidden external-launcher flags `--notte-api`
|
|
117
|
+
(boolean) and `--notte-user VALUE` are accepted for compatibility; any other
|
|
118
|
+
unknown flag fails normally.
|
|
107
119
|
|
|
108
120
|
### Status
|
|
109
121
|
|
|
@@ -111,16 +123,26 @@ Display operational status, running PIDs, connection URLs, and security settings
|
|
|
111
123
|
|
|
112
124
|
```bash
|
|
113
125
|
nullgate status
|
|
126
|
+
nullgate status --json
|
|
114
127
|
```
|
|
115
128
|
|
|
129
|
+
When stdout is not a TTY, `status` emits only a directly usable SSH fallback
|
|
130
|
+
command plus a `password: VALUE` line when a generated password exists; with no
|
|
131
|
+
live target it prints `stopped` or `pending`. `--json` is the stable full
|
|
132
|
+
machine interface.
|
|
133
|
+
|
|
116
134
|
### Connect
|
|
117
135
|
|
|
118
136
|
Print client connection strings and OpenSSH client configuration directives:
|
|
119
137
|
|
|
120
138
|
```bash
|
|
121
139
|
nullgate connect
|
|
140
|
+
nullgate connect --json
|
|
122
141
|
```
|
|
123
142
|
|
|
143
|
+
On an interactive TTY `connect` keeps the setup instructions; piped output
|
|
144
|
+
emits only the directly usable fallback command.
|
|
145
|
+
|
|
124
146
|
### Logs
|
|
125
147
|
|
|
126
148
|
Stream or print daemon logs:
|
|
@@ -142,7 +164,10 @@ nullgate stop
|
|
|
142
164
|
|
|
143
165
|
### Restart
|
|
144
166
|
|
|
145
|
-
Restart daemon instances reusing
|
|
167
|
+
Restart daemon instances reusing the saved workspace, provider, port, and
|
|
168
|
+
security settings from the previous start. A direct `--identity-seed` value
|
|
169
|
+
from the original start is intentionally not persisted, so `restart` cannot
|
|
170
|
+
reuse it; only the seed-file path is saved and revalidated.
|
|
146
171
|
|
|
147
172
|
```bash
|
|
148
173
|
nullgate restart
|
|
@@ -161,10 +186,12 @@ Short command aliases are `up`, `down`, `ps`, `ssh`, `log`, and `reload`.
|
|
|
161
186
|
The earlier names `open`, `shut`, `inspect`, `enter`, `trace`, and `cycle`
|
|
162
187
|
remain available as compatibility aliases. Their earlier option names also
|
|
163
188
|
remain accepted, but new scripts should use the names documented above.
|
|
189
|
+
Unknown flags fail normally; only the hidden external-launcher flags
|
|
190
|
+
`--notte-api` (boolean) and `--notte-user VALUE` are accepted as no-ops.
|
|
164
191
|
|
|
165
192
|
## Authentication and Security Boundaries
|
|
166
193
|
|
|
167
|
-
- **Authentication Baseline**:
|
|
194
|
+
- **Authentication Baseline**: Authenticated access is the default. Pass `--public-access` to allow connections without credentials (unsafe on public endpoints). Without it, srv.us secure startup uses authorized SSH keys from `~/.ssh/authorized_keys` and/or a generated high-entropy password stored in the runtime directory.
|
|
168
195
|
- **Public access (`--public-access`)**: Bypasses authentication checks entirely; any incoming connection with network access is accepted.
|
|
169
196
|
- **Upterm Transport**: Relies on authorized SSH public keys or `--public-access` (Upterm does not support password authentication). The relay itself is trusted for inbound multiplexing.
|
|
170
197
|
- **Filesystem Confinement**: SFTP and SCP access cannot escape the designated workspace directory.
|
|
@@ -178,7 +205,7 @@ remain accepted, but new scripts should use the names documented above.
|
|
|
178
205
|
|---|---|
|
|
179
206
|
| `NULLGATE_PASSWORD` | Gateway-process credential; normally managed internally by `nullgate start` |
|
|
180
207
|
| `NULLGATE_STATE_DIR` | Directory holding runtime state and logs (defaults to `~/.local/state/nullgate`) |
|
|
181
|
-
| `NULLGATE_IDENTITY_SEED` | Seed
|
|
208
|
+
| `NULLGATE_IDENTITY_SEED` | Seed for deterministic Ed25519 key derivation; only used when creating the identity file, never when it already exists |
|
|
182
209
|
| `NULLGATE_TUNNEL_HOST` | Host address for srv.us ingress (default: `srv.us`) |
|
|
183
210
|
| `NULLGATE_TUNNEL_PORT` | Port for srv.us ingress (default: `22`) |
|
|
184
211
|
| `NULLGATE_CLOUDFLARED_TOKEN` | Credential token for `cloudflared` tunnels |
|
|
@@ -186,6 +213,42 @@ remain accepted, but new scripts should use the names documented above.
|
|
|
186
213
|
| `NULLGATE_VERSION` | Install a specific published version instead of the stable release; accepts `1.0.1` or `v1.0.1` |
|
|
187
214
|
| `NULLGATE_DIST_URL` | Override the public release channel used by `install.sh` |
|
|
188
215
|
| `NULLGATE_INSTALL_URL` | Override the installer URL used by `nullgate upgrade` |
|
|
216
|
+
| `NO_COLOR` | Set to any value to disable ANSI color output (non-TTY output never uses color) |
|
|
217
|
+
|
|
218
|
+
## Automation/CI
|
|
219
|
+
|
|
220
|
+
- Noninteractive runs never prompt: with stdin closed or piped, `start` skips
|
|
221
|
+
the key prompt and generates the password for srv.us secure mode. Upterm
|
|
222
|
+
secure mode without authorized keys fails immediately instead of hanging.
|
|
223
|
+
- Readiness is decisive: `start` returns success only after the gateway
|
|
224
|
+
listens, the transport stays alive, and (for srv.us) a hostname is
|
|
225
|
+
announced. On timeout or failure both processes are stopped, recent
|
|
226
|
+
transport logs go to stderr, and the exit code is nonzero.
|
|
227
|
+
- `start --foreground` keeps the parent alive supervising both children,
|
|
228
|
+
handles SIGINT/SIGTERM by stopping them, and exits nonzero with recent log tails if
|
|
229
|
+
either child dies. Background start remains the default.
|
|
230
|
+
- `start`, `status`, and `connect` accept `--json` for machine-readable
|
|
231
|
+
output. JSON is the only stdout in JSON mode and carries the operational
|
|
232
|
+
fields agents need: version, provider, running state and PIDs, port,
|
|
233
|
+
workspace, URL, host, user, proxy command, auth mode, TCP forwarding, and
|
|
234
|
+
file-transfer mode. `--json` is the stable agent contract; human output may
|
|
235
|
+
change. `start --foreground --json` prints one readiness object,
|
|
236
|
+
flushes it, then supervises.
|
|
237
|
+
- Piped output is compact: successful `start`, `status`, and `connect` with a
|
|
238
|
+
target emit only a directly usable SSH fallback command plus one
|
|
239
|
+
`password: VALUE` line when a generated password exists. With no live
|
|
240
|
+
usable target, `status` prints `stopped` or `pending`.
|
|
241
|
+
- Identity seeds: `--identity-seed-file PATH` keeps the value out of argv
|
|
242
|
+
and history (flag overrides `NULLGATE_IDENTITY_SEED`); `--identity-seed
|
|
243
|
+
VALUE` is also accepted but is visible in argv and shell history. Both apply
|
|
244
|
+
only to the srv.us provider, fail before launch when absent, unreadable, or
|
|
245
|
+
empty (direct value: nonempty after stripping), pass the seed only to the
|
|
246
|
+
srv.us child environment (every other child gets a seed-free environment even
|
|
247
|
+
when the parent exported one), and never print or persist the value. Only the
|
|
248
|
+
seed-file path is saved for `restart`, which revalidates the saved srv.us seed
|
|
249
|
+
file before stopping anything; a direct `--identity-seed` from the original
|
|
250
|
+
start is intentionally not persisted, so `restart` cannot reuse it. The seed
|
|
251
|
+
only takes effect when the identity key does not yet exist.
|
|
189
252
|
|
|
190
253
|
## Development
|
|
191
254
|
|
|
@@ -7,7 +7,7 @@ Disposable SSH gateway into confined directory workspaces for remote containers,
|
|
|
7
7
|
Run Nullgate directly from PyPI without installing it first:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
# Share the current directory over the default
|
|
10
|
+
# Share the current directory over the default srv.us provider
|
|
11
11
|
uvx nullgate start
|
|
12
12
|
|
|
13
13
|
# Share a specific workspace
|
|
@@ -24,13 +24,13 @@ uvx nullgate status
|
|
|
24
24
|
uvx nullgate connect
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Nullgate
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
Nullgate requires authentication by default (an authorized SSH key and/or a
|
|
28
|
+
generated password). Pass `--public-access` to allow connections without
|
|
29
|
+
credentials (unsafe on public endpoints).
|
|
30
30
|
|
|
31
31
|
## Features
|
|
32
32
|
|
|
33
|
-
- **Ingress Transports**: Publish endpoints via
|
|
33
|
+
- **Ingress Transports**: Publish endpoints via srv.us reverse tunnels (default), Upterm WebSocket relays, Cloudflare Worker relays, or Cloudflare Argo (`cloudflared`) tunnels.
|
|
34
34
|
- **Confinement**: SFTP and SCP workloads are restricted to the designated workspace root; parent traversals and out-of-root symlinks are blocked.
|
|
35
35
|
- **Host file visibility**: Relative transfer paths begin in the workspace root while absolute paths address host locations, matching shell behavior; add `--restrict-file-transfer` for strict workspace-only transfers.
|
|
36
36
|
- **Direct Shell Access**: Authenticated PTY sessions run interactively under the local user credentials.
|
|
@@ -60,10 +60,12 @@ pip install nullgate
|
|
|
60
60
|
|
|
61
61
|
### Start
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
Start the gateway service and ingress transport, then report readiness once the
|
|
64
|
+
gateway listens, the transport stays alive, and srv.us has announced a
|
|
65
|
+
hostname (for that provider):
|
|
64
66
|
|
|
65
67
|
```bash
|
|
66
|
-
# Default
|
|
68
|
+
# Default srv.us transport on port 4822 sharing current directory
|
|
67
69
|
nullgate start
|
|
68
70
|
|
|
69
71
|
# Custom path, port, and slot
|
|
@@ -82,16 +84,26 @@ nullgate start . --provider cloudflared --public-hostname workspace.example.com
|
|
|
82
84
|
Options:
|
|
83
85
|
- `-p`, `--ssh-port`: Local SSH server port.
|
|
84
86
|
- `-s`, `--tunnel-slot`: srv.us tunnel slot.
|
|
85
|
-
- `-t`, `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `
|
|
87
|
+
- `-t`, `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `srvus`.
|
|
86
88
|
- `-e`, `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
|
|
87
89
|
- `-H`, `--public-hostname`: Public hostname used with `cloudflared`.
|
|
88
90
|
- `--cloudflare-token`: Cloudflare tunnel credential, or set `NULLGATE_CLOUDFLARED_TOKEN`.
|
|
89
|
-
- `--
|
|
91
|
+
- `--identity-seed VALUE`: srv.us identity seed value (visible in argv and shell history; flag overrides seed file and `NULLGATE_IDENTITY_SEED`; other providers ignore it). Prefer `--identity-seed-file PATH` to avoid history exposure. The direct value is never printed or saved; `restart` cannot reuse it because only the seed-file path is persisted. The seed only matters when the identity key does not yet exist.
|
|
92
|
+
- `--identity-seed-file PATH`: Read the srv.us identity seed from a file (overrides `NULLGATE_IDENTITY_SEED`; other providers ignore it). The file must hold nonempty UTF-8 text; only the path is saved for `restart`, never the seed value. `restart` revalidates the saved file before stopping the running session. The seed only matters when the identity key does not yet exist.
|
|
93
|
+
- `--public-access`: Allow connections without credentials (unsafe on public endpoints). Off by default; only `restart` reuses a saved setting, a fresh `start` always defaults to authenticated access.
|
|
90
94
|
- `--no-public-access`: Require authentication.
|
|
91
|
-
- `--tcp-forwarding`:
|
|
92
|
-
- `--no-tcp-forwarding`: Disable SSH TCP tunneling.
|
|
95
|
+
- `--tcp-forwarding`: Allow SSH TCP tunneling (`ssh -L`; enabled by default on fresh `start`).
|
|
96
|
+
- `--no-tcp-forwarding`: Disable SSH TCP tunneling. `restart` reuses the saved effective setting.
|
|
93
97
|
- `--restrict-file-transfer`: Keep SFTP and SCP inside the workspace.
|
|
94
98
|
- `--no-restrict-file-transfer`: Allow host-visible file transfers.
|
|
99
|
+
- `--foreground`: Stay in the foreground and supervise gateway and transport instead of exiting after readiness. The parent handles SIGINT and SIGTERM and stops both children, exiting nonzero with recent log tails if either child dies.
|
|
100
|
+
- `--json`: Emit machine-readable JSON on stdout (the only stdout in JSON mode). `start --foreground --json` prints one readiness object, flushes it, then supervises.
|
|
101
|
+
|
|
102
|
+
A fresh `start` uses documented defaults and the current directory when no
|
|
103
|
+
workspace is given; only `restart` reuses saved workspace, provider, port,
|
|
104
|
+
and security settings. Only the hidden external-launcher flags `--notte-api`
|
|
105
|
+
(boolean) and `--notte-user VALUE` are accepted for compatibility; any other
|
|
106
|
+
unknown flag fails normally.
|
|
95
107
|
|
|
96
108
|
### Status
|
|
97
109
|
|
|
@@ -99,16 +111,26 @@ Display operational status, running PIDs, connection URLs, and security settings
|
|
|
99
111
|
|
|
100
112
|
```bash
|
|
101
113
|
nullgate status
|
|
114
|
+
nullgate status --json
|
|
102
115
|
```
|
|
103
116
|
|
|
117
|
+
When stdout is not a TTY, `status` emits only a directly usable SSH fallback
|
|
118
|
+
command plus a `password: VALUE` line when a generated password exists; with no
|
|
119
|
+
live target it prints `stopped` or `pending`. `--json` is the stable full
|
|
120
|
+
machine interface.
|
|
121
|
+
|
|
104
122
|
### Connect
|
|
105
123
|
|
|
106
124
|
Print client connection strings and OpenSSH client configuration directives:
|
|
107
125
|
|
|
108
126
|
```bash
|
|
109
127
|
nullgate connect
|
|
128
|
+
nullgate connect --json
|
|
110
129
|
```
|
|
111
130
|
|
|
131
|
+
On an interactive TTY `connect` keeps the setup instructions; piped output
|
|
132
|
+
emits only the directly usable fallback command.
|
|
133
|
+
|
|
112
134
|
### Logs
|
|
113
135
|
|
|
114
136
|
Stream or print daemon logs:
|
|
@@ -130,7 +152,10 @@ nullgate stop
|
|
|
130
152
|
|
|
131
153
|
### Restart
|
|
132
154
|
|
|
133
|
-
Restart daemon instances reusing
|
|
155
|
+
Restart daemon instances reusing the saved workspace, provider, port, and
|
|
156
|
+
security settings from the previous start. A direct `--identity-seed` value
|
|
157
|
+
from the original start is intentionally not persisted, so `restart` cannot
|
|
158
|
+
reuse it; only the seed-file path is saved and revalidated.
|
|
134
159
|
|
|
135
160
|
```bash
|
|
136
161
|
nullgate restart
|
|
@@ -149,10 +174,12 @@ Short command aliases are `up`, `down`, `ps`, `ssh`, `log`, and `reload`.
|
|
|
149
174
|
The earlier names `open`, `shut`, `inspect`, `enter`, `trace`, and `cycle`
|
|
150
175
|
remain available as compatibility aliases. Their earlier option names also
|
|
151
176
|
remain accepted, but new scripts should use the names documented above.
|
|
177
|
+
Unknown flags fail normally; only the hidden external-launcher flags
|
|
178
|
+
`--notte-api` (boolean) and `--notte-user VALUE` are accepted as no-ops.
|
|
152
179
|
|
|
153
180
|
## Authentication and Security Boundaries
|
|
154
181
|
|
|
155
|
-
- **Authentication Baseline**:
|
|
182
|
+
- **Authentication Baseline**: Authenticated access is the default. Pass `--public-access` to allow connections without credentials (unsafe on public endpoints). Without it, srv.us secure startup uses authorized SSH keys from `~/.ssh/authorized_keys` and/or a generated high-entropy password stored in the runtime directory.
|
|
156
183
|
- **Public access (`--public-access`)**: Bypasses authentication checks entirely; any incoming connection with network access is accepted.
|
|
157
184
|
- **Upterm Transport**: Relies on authorized SSH public keys or `--public-access` (Upterm does not support password authentication). The relay itself is trusted for inbound multiplexing.
|
|
158
185
|
- **Filesystem Confinement**: SFTP and SCP access cannot escape the designated workspace directory.
|
|
@@ -166,7 +193,7 @@ remain accepted, but new scripts should use the names documented above.
|
|
|
166
193
|
|---|---|
|
|
167
194
|
| `NULLGATE_PASSWORD` | Gateway-process credential; normally managed internally by `nullgate start` |
|
|
168
195
|
| `NULLGATE_STATE_DIR` | Directory holding runtime state and logs (defaults to `~/.local/state/nullgate`) |
|
|
169
|
-
| `NULLGATE_IDENTITY_SEED` | Seed
|
|
196
|
+
| `NULLGATE_IDENTITY_SEED` | Seed for deterministic Ed25519 key derivation; only used when creating the identity file, never when it already exists |
|
|
170
197
|
| `NULLGATE_TUNNEL_HOST` | Host address for srv.us ingress (default: `srv.us`) |
|
|
171
198
|
| `NULLGATE_TUNNEL_PORT` | Port for srv.us ingress (default: `22`) |
|
|
172
199
|
| `NULLGATE_CLOUDFLARED_TOKEN` | Credential token for `cloudflared` tunnels |
|
|
@@ -174,6 +201,42 @@ remain accepted, but new scripts should use the names documented above.
|
|
|
174
201
|
| `NULLGATE_VERSION` | Install a specific published version instead of the stable release; accepts `1.0.1` or `v1.0.1` |
|
|
175
202
|
| `NULLGATE_DIST_URL` | Override the public release channel used by `install.sh` |
|
|
176
203
|
| `NULLGATE_INSTALL_URL` | Override the installer URL used by `nullgate upgrade` |
|
|
204
|
+
| `NO_COLOR` | Set to any value to disable ANSI color output (non-TTY output never uses color) |
|
|
205
|
+
|
|
206
|
+
## Automation/CI
|
|
207
|
+
|
|
208
|
+
- Noninteractive runs never prompt: with stdin closed or piped, `start` skips
|
|
209
|
+
the key prompt and generates the password for srv.us secure mode. Upterm
|
|
210
|
+
secure mode without authorized keys fails immediately instead of hanging.
|
|
211
|
+
- Readiness is decisive: `start` returns success only after the gateway
|
|
212
|
+
listens, the transport stays alive, and (for srv.us) a hostname is
|
|
213
|
+
announced. On timeout or failure both processes are stopped, recent
|
|
214
|
+
transport logs go to stderr, and the exit code is nonzero.
|
|
215
|
+
- `start --foreground` keeps the parent alive supervising both children,
|
|
216
|
+
handles SIGINT/SIGTERM by stopping them, and exits nonzero with recent log tails if
|
|
217
|
+
either child dies. Background start remains the default.
|
|
218
|
+
- `start`, `status`, and `connect` accept `--json` for machine-readable
|
|
219
|
+
output. JSON is the only stdout in JSON mode and carries the operational
|
|
220
|
+
fields agents need: version, provider, running state and PIDs, port,
|
|
221
|
+
workspace, URL, host, user, proxy command, auth mode, TCP forwarding, and
|
|
222
|
+
file-transfer mode. `--json` is the stable agent contract; human output may
|
|
223
|
+
change. `start --foreground --json` prints one readiness object,
|
|
224
|
+
flushes it, then supervises.
|
|
225
|
+
- Piped output is compact: successful `start`, `status`, and `connect` with a
|
|
226
|
+
target emit only a directly usable SSH fallback command plus one
|
|
227
|
+
`password: VALUE` line when a generated password exists. With no live
|
|
228
|
+
usable target, `status` prints `stopped` or `pending`.
|
|
229
|
+
- Identity seeds: `--identity-seed-file PATH` keeps the value out of argv
|
|
230
|
+
and history (flag overrides `NULLGATE_IDENTITY_SEED`); `--identity-seed
|
|
231
|
+
VALUE` is also accepted but is visible in argv and shell history. Both apply
|
|
232
|
+
only to the srv.us provider, fail before launch when absent, unreadable, or
|
|
233
|
+
empty (direct value: nonempty after stripping), pass the seed only to the
|
|
234
|
+
srv.us child environment (every other child gets a seed-free environment even
|
|
235
|
+
when the parent exported one), and never print or persist the value. Only the
|
|
236
|
+
seed-file path is saved for `restart`, which revalidates the saved srv.us seed
|
|
237
|
+
file before stopping anything; a direct `--identity-seed` from the original
|
|
238
|
+
start is intentionally not persisted, so `restart` cannot reuse it. The seed
|
|
239
|
+
only takes effect when the identity key does not yet exist.
|
|
177
240
|
|
|
178
241
|
## Development
|
|
179
242
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.2.5"
|
|
@@ -118,7 +118,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
118
118
|
dest="allow_tcp_forwarding",
|
|
119
119
|
action=argparse.BooleanOptionalAction,
|
|
120
120
|
default=None,
|
|
121
|
-
help="Allow SSH port forwarding.",
|
|
121
|
+
help="Allow SSH port forwarding (enabled by default; --no-tcp-forwarding disables).",
|
|
122
122
|
)
|
|
123
123
|
start_parser.add_argument(
|
|
124
124
|
"--allow-tcp-forwarding",
|
|
@@ -161,6 +161,43 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
161
161
|
help="Cloudflare tunnel token (for the cloudflared provider).",
|
|
162
162
|
)
|
|
163
163
|
start_parser.add_argument("--token", dest="token", help=argparse.SUPPRESS)
|
|
164
|
+
seed_group = start_parser.add_mutually_exclusive_group()
|
|
165
|
+
seed_group.add_argument(
|
|
166
|
+
"--identity-seed",
|
|
167
|
+
dest="identity_seed",
|
|
168
|
+
metavar="VALUE",
|
|
169
|
+
default=None,
|
|
170
|
+
help="srv.us identity seed value (visible in argv/history; ignored by other providers).",
|
|
171
|
+
)
|
|
172
|
+
seed_group.add_argument(
|
|
173
|
+
"--identity-seed-file",
|
|
174
|
+
dest="identity_seed_file",
|
|
175
|
+
metavar="PATH",
|
|
176
|
+
default=None,
|
|
177
|
+
help="File holding the srv.us identity seed (overrides NULLGATE_IDENTITY_SEED; ignored by other providers).",
|
|
178
|
+
)
|
|
179
|
+
start_parser.add_argument(
|
|
180
|
+
"--foreground",
|
|
181
|
+
dest="foreground",
|
|
182
|
+
action="store_true",
|
|
183
|
+
help="Stay in the foreground and supervise gateway and transport.",
|
|
184
|
+
)
|
|
185
|
+
start_parser.add_argument(
|
|
186
|
+
"--json",
|
|
187
|
+
dest="json",
|
|
188
|
+
action="store_true",
|
|
189
|
+
help="Emit machine-readable JSON on stdout.",
|
|
190
|
+
)
|
|
191
|
+
start_parser.add_argument(
|
|
192
|
+
"--notte-api", dest="notte_api", action="store_true", help=argparse.SUPPRESS
|
|
193
|
+
)
|
|
194
|
+
start_parser.add_argument(
|
|
195
|
+
"--notte-user",
|
|
196
|
+
dest="notte_user",
|
|
197
|
+
metavar="VALUE",
|
|
198
|
+
default=None,
|
|
199
|
+
help=argparse.SUPPRESS,
|
|
200
|
+
)
|
|
164
201
|
|
|
165
202
|
sub.add_parser(
|
|
166
203
|
"stop",
|
|
@@ -169,19 +206,31 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
169
206
|
help="Stop SSH access (aliases: down, shut).",
|
|
170
207
|
)
|
|
171
208
|
|
|
172
|
-
sub.add_parser(
|
|
209
|
+
status_parser = sub.add_parser(
|
|
173
210
|
"status",
|
|
174
211
|
aliases=["ps", "inspect"],
|
|
175
212
|
description="Show service health, connection details, and security settings.",
|
|
176
213
|
help="Show current status (aliases: ps, inspect).",
|
|
177
214
|
)
|
|
215
|
+
status_parser.add_argument(
|
|
216
|
+
"--json",
|
|
217
|
+
dest="json",
|
|
218
|
+
action="store_true",
|
|
219
|
+
help="Emit machine-readable JSON on stdout.",
|
|
220
|
+
)
|
|
178
221
|
|
|
179
|
-
sub.add_parser(
|
|
222
|
+
connect_parser = sub.add_parser(
|
|
180
223
|
"connect",
|
|
181
224
|
aliases=["ssh", "enter"],
|
|
182
225
|
description="Show how to connect with SSH.",
|
|
183
226
|
help="Show SSH connection instructions (aliases: ssh, enter).",
|
|
184
227
|
)
|
|
228
|
+
connect_parser.add_argument(
|
|
229
|
+
"--json",
|
|
230
|
+
dest="json",
|
|
231
|
+
action="store_true",
|
|
232
|
+
help="Emit machine-readable JSON on stdout.",
|
|
233
|
+
)
|
|
185
234
|
|
|
186
235
|
logs_parser = sub.add_parser(
|
|
187
236
|
"logs",
|
|
@@ -238,7 +287,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
238
287
|
|
|
239
288
|
def main(argv: Sequence[str] | None = None) -> int:
|
|
240
289
|
parser = build_parser()
|
|
241
|
-
|
|
290
|
+
supplied = list(sys.argv[1:] if argv is None else argv)
|
|
291
|
+
if supplied in (["--help"], ["api", "--help"]):
|
|
292
|
+
supplied = ["start"]
|
|
293
|
+
args = parser.parse_args(supplied)
|
|
242
294
|
|
|
243
295
|
handlers = {
|
|
244
296
|
"start": session.cmd_open,
|