nullgate 1.2.4__tar.gz → 1.2.6__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.4/src/nullgate.egg-info → nullgate-1.2.6}/PKG-INFO +77 -12
- {nullgate-1.2.4 → nullgate-1.2.6}/README.md +76 -11
- nullgate-1.2.6/src/nullgate/__init__.py +1 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate/commands.py +64 -39
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate/session.py +362 -34
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate/transports.py +73 -20
- {nullgate-1.2.4 → nullgate-1.2.6/src/nullgate.egg-info}/PKG-INFO +77 -12
- nullgate-1.2.6/tests/test_commands.py +2347 -0
- nullgate-1.2.4/src/nullgate/__init__.py +0 -1
- nullgate-1.2.4/tests/test_commands.py +0 -770
- {nullgate-1.2.4 → nullgate-1.2.6}/LICENSE +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/pyproject.toml +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/setup.cfg +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate/account.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate/bridge.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate/client_config.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate/gateway.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate/ingress.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate/runtime.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate/wsroute.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate.egg-info/SOURCES.txt +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate.egg-info/dependency_links.txt +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate.egg-info/entry_points.txt +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate.egg-info/requires.txt +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/src/nullgate.egg-info/top_level.txt +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/tests/test_account.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/tests/test_bridge.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/tests/test_gateway.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/tests/test_ingress.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/tests/test_install.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.6}/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.6
|
|
4
4
|
Summary: Disposable SSH gateway into confined directory workspaces
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -36,8 +36,9 @@ uvx nullgate status
|
|
|
36
36
|
uvx nullgate connect
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Nullgate
|
|
40
|
-
`--
|
|
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).
|
|
41
42
|
|
|
42
43
|
## Features
|
|
43
44
|
|
|
@@ -71,7 +72,9 @@ pip install nullgate
|
|
|
71
72
|
|
|
72
73
|
### Start
|
|
73
74
|
|
|
74
|
-
|
|
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):
|
|
75
78
|
|
|
76
79
|
```bash
|
|
77
80
|
# Default srv.us transport on port 4822 sharing current directory
|
|
@@ -97,12 +100,24 @@ Options:
|
|
|
97
100
|
- `-e`, `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
|
|
98
101
|
- `-H`, `--public-hostname`: Public hostname used with `cloudflared`.
|
|
99
102
|
- `--cloudflare-token`: Cloudflare tunnel credential, or set `NULLGATE_CLOUDFLARED_TOKEN`.
|
|
100
|
-
- `--
|
|
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.
|
|
101
106
|
- `--no-public-access`: Require authentication.
|
|
102
|
-
- `--tcp-forwarding`:
|
|
103
|
-
- `--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.
|
|
104
109
|
- `--restrict-file-transfer`: Keep SFTP and SCP inside the workspace.
|
|
105
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
|
+
- `--replace-stale`: Replace tracked gateway and transport processes when they are not healthy. Healthy srv.us sessions are reused.
|
|
114
|
+
- `--rendezvous-url URL`: After srv.us passes its public SSH-over-TLS check, POST a minimal readiness document. Defaults to `NULLGATE_RENDEZVOUS_URL` and is saved for `restart`; the URL is never printed.
|
|
115
|
+
|
|
116
|
+
A fresh `start` uses documented defaults and the current directory when no
|
|
117
|
+
workspace is given; only `restart` reuses saved workspace, provider, port,
|
|
118
|
+
and security settings. Only the hidden external-launcher flags `--notte-api`
|
|
119
|
+
(boolean) and `--notte-user VALUE` are accepted for compatibility; any other
|
|
120
|
+
unknown flag fails normally.
|
|
106
121
|
|
|
107
122
|
### Status
|
|
108
123
|
|
|
@@ -110,16 +125,26 @@ Display operational status, running PIDs, connection URLs, and security settings
|
|
|
110
125
|
|
|
111
126
|
```bash
|
|
112
127
|
nullgate status
|
|
128
|
+
nullgate status --json
|
|
113
129
|
```
|
|
114
130
|
|
|
131
|
+
When stdout is not a TTY, `status` emits only a directly usable SSH fallback
|
|
132
|
+
command plus a `password: VALUE` line when a generated password exists; with no
|
|
133
|
+
live target it prints `stopped` or `pending`. `--json` is the stable full
|
|
134
|
+
machine interface.
|
|
135
|
+
|
|
115
136
|
### Connect
|
|
116
137
|
|
|
117
138
|
Print client connection strings and OpenSSH client configuration directives:
|
|
118
139
|
|
|
119
140
|
```bash
|
|
120
141
|
nullgate connect
|
|
142
|
+
nullgate connect --json
|
|
121
143
|
```
|
|
122
144
|
|
|
145
|
+
On an interactive TTY `connect` keeps the setup instructions; piped output
|
|
146
|
+
emits only the directly usable fallback command.
|
|
147
|
+
|
|
123
148
|
### Logs
|
|
124
149
|
|
|
125
150
|
Stream or print daemon logs:
|
|
@@ -141,7 +166,10 @@ nullgate stop
|
|
|
141
166
|
|
|
142
167
|
### Restart
|
|
143
168
|
|
|
144
|
-
Restart daemon instances reusing
|
|
169
|
+
Restart daemon instances reusing the saved workspace, provider, port, and
|
|
170
|
+
security settings from the previous start. A direct `--identity-seed` value
|
|
171
|
+
from the original start is intentionally not persisted, so `restart` cannot
|
|
172
|
+
reuse it; only the seed-file path is saved and revalidated.
|
|
145
173
|
|
|
146
174
|
```bash
|
|
147
175
|
nullgate restart
|
|
@@ -160,12 +188,12 @@ Short command aliases are `up`, `down`, `ps`, `ssh`, `log`, and `reload`.
|
|
|
160
188
|
The earlier names `open`, `shut`, `inspect`, `enter`, `trace`, and `cycle`
|
|
161
189
|
remain available as compatibility aliases. Their earlier option names also
|
|
162
190
|
remain accepted, but new scripts should use the names documented above.
|
|
163
|
-
Unknown flags
|
|
164
|
-
|
|
191
|
+
Unknown flags fail normally; only the hidden external-launcher flags
|
|
192
|
+
`--notte-api` (boolean) and `--notte-user VALUE` are accepted as no-ops.
|
|
165
193
|
|
|
166
194
|
## Authentication and Security Boundaries
|
|
167
195
|
|
|
168
|
-
- **Authentication Baseline**:
|
|
196
|
+
- **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.
|
|
169
197
|
- **Public access (`--public-access`)**: Bypasses authentication checks entirely; any incoming connection with network access is accepted.
|
|
170
198
|
- **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.
|
|
171
199
|
- **Filesystem Confinement**: SFTP and SCP access cannot escape the designated workspace directory.
|
|
@@ -179,14 +207,51 @@ external launchers.
|
|
|
179
207
|
|---|---|
|
|
180
208
|
| `NULLGATE_PASSWORD` | Gateway-process credential; normally managed internally by `nullgate start` |
|
|
181
209
|
| `NULLGATE_STATE_DIR` | Directory holding runtime state and logs (defaults to `~/.local/state/nullgate`) |
|
|
182
|
-
| `NULLGATE_IDENTITY_SEED` | Seed
|
|
210
|
+
| `NULLGATE_IDENTITY_SEED` | Seed for deterministic Ed25519 key derivation; only used when creating the identity file, never when it already exists |
|
|
183
211
|
| `NULLGATE_TUNNEL_HOST` | Host address for srv.us ingress (default: `srv.us`) |
|
|
184
212
|
| `NULLGATE_TUNNEL_PORT` | Port for srv.us ingress (default: `22`) |
|
|
185
213
|
| `NULLGATE_CLOUDFLARED_TOKEN` | Credential token for `cloudflared` tunnels |
|
|
186
214
|
| `NULLGATE_CONFINE_SFTP` | Set to `1` to confine SFTP and SCP transfers to the workspace root |
|
|
215
|
+
| `NULLGATE_RENDEZVOUS_URL` | HTTP endpoint for publishing successful srv.us readiness; may contain a secret token and is never printed |
|
|
187
216
|
| `NULLGATE_VERSION` | Install a specific published version instead of the stable release; accepts `1.0.1` or `v1.0.1` |
|
|
188
217
|
| `NULLGATE_DIST_URL` | Override the public release channel used by `install.sh` |
|
|
189
218
|
| `NULLGATE_INSTALL_URL` | Override the installer URL used by `nullgate upgrade` |
|
|
219
|
+
| `NO_COLOR` | Set to any value to disable ANSI color output (non-TTY output never uses color) |
|
|
220
|
+
|
|
221
|
+
## Automation/CI
|
|
222
|
+
|
|
223
|
+
- Noninteractive runs never prompt: with stdin closed or piped, `start` skips
|
|
224
|
+
the key prompt and generates the password for srv.us secure mode. Upterm
|
|
225
|
+
secure mode without authorized keys fails immediately instead of hanging.
|
|
226
|
+
- Readiness is decisive: `start` returns success only after the gateway
|
|
227
|
+
listens, the transport stays alive, and (for srv.us) a hostname is
|
|
228
|
+
announced and serves an SSH banner over certificate-validated TLS. On timeout or failure both processes are stopped, recent
|
|
229
|
+
transport logs go to stderr, and the exit code is nonzero.
|
|
230
|
+
- `start --foreground` keeps the parent alive supervising both children,
|
|
231
|
+
handles SIGINT/SIGTERM by stopping them, and exits nonzero with recent log tails if
|
|
232
|
+
either child dies. Background start remains the default.
|
|
233
|
+
- `start`, `status`, and `connect` accept `--json` for machine-readable
|
|
234
|
+
output. JSON is the only stdout in JSON mode and carries the operational
|
|
235
|
+
fields agents need: version, provider, running state and PIDs, port,
|
|
236
|
+
workspace, URL, host, user, proxy command, public health, auth mode, TCP forwarding, and
|
|
237
|
+
file-transfer mode. `--json` is the stable agent contract; human output may
|
|
238
|
+
change. `start --foreground --json` prints one readiness object,
|
|
239
|
+
flushes it, then supervises.
|
|
240
|
+
- Piped output is compact: successful `start`, `status`, and `connect` with a
|
|
241
|
+
target emit only a directly usable SSH fallback command plus one
|
|
242
|
+
`password: VALUE` line when a generated password exists. With no live
|
|
243
|
+
usable target, `status` prints `stopped` or `pending`.
|
|
244
|
+
- Identity seeds: `--identity-seed-file PATH` keeps the value out of argv
|
|
245
|
+
and history (flag overrides `NULLGATE_IDENTITY_SEED`); `--identity-seed
|
|
246
|
+
VALUE` is also accepted but is visible in argv and shell history. Both apply
|
|
247
|
+
only to the srv.us provider, fail before launch when absent, unreadable, or
|
|
248
|
+
empty (direct value: nonempty after stripping), pass the seed only to the
|
|
249
|
+
srv.us child environment (every other child gets a seed-free environment even
|
|
250
|
+
when the parent exported one), and never print or persist the value. Only the
|
|
251
|
+
seed-file path is saved for `restart`, which revalidates the saved srv.us seed
|
|
252
|
+
file before stopping anything; a direct `--identity-seed` from the original
|
|
253
|
+
start is intentionally not persisted, so `restart` cannot reuse it. The seed
|
|
254
|
+
only takes effect when the identity key does not yet exist.
|
|
190
255
|
|
|
191
256
|
## Development
|
|
192
257
|
|
|
@@ -24,8 +24,9 @@ uvx nullgate status
|
|
|
24
24
|
uvx nullgate connect
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Nullgate
|
|
28
|
-
`--
|
|
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).
|
|
29
30
|
|
|
30
31
|
## Features
|
|
31
32
|
|
|
@@ -59,7 +60,9 @@ pip install nullgate
|
|
|
59
60
|
|
|
60
61
|
### Start
|
|
61
62
|
|
|
62
|
-
|
|
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):
|
|
63
66
|
|
|
64
67
|
```bash
|
|
65
68
|
# Default srv.us transport on port 4822 sharing current directory
|
|
@@ -85,12 +88,24 @@ Options:
|
|
|
85
88
|
- `-e`, `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
|
|
86
89
|
- `-H`, `--public-hostname`: Public hostname used with `cloudflared`.
|
|
87
90
|
- `--cloudflare-token`: Cloudflare tunnel credential, or set `NULLGATE_CLOUDFLARED_TOKEN`.
|
|
88
|
-
- `--
|
|
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.
|
|
89
94
|
- `--no-public-access`: Require authentication.
|
|
90
|
-
- `--tcp-forwarding`:
|
|
91
|
-
- `--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.
|
|
92
97
|
- `--restrict-file-transfer`: Keep SFTP and SCP inside the workspace.
|
|
93
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
|
+
- `--replace-stale`: Replace tracked gateway and transport processes when they are not healthy. Healthy srv.us sessions are reused.
|
|
102
|
+
- `--rendezvous-url URL`: After srv.us passes its public SSH-over-TLS check, POST a minimal readiness document. Defaults to `NULLGATE_RENDEZVOUS_URL` and is saved for `restart`; the URL is never printed.
|
|
103
|
+
|
|
104
|
+
A fresh `start` uses documented defaults and the current directory when no
|
|
105
|
+
workspace is given; only `restart` reuses saved workspace, provider, port,
|
|
106
|
+
and security settings. Only the hidden external-launcher flags `--notte-api`
|
|
107
|
+
(boolean) and `--notte-user VALUE` are accepted for compatibility; any other
|
|
108
|
+
unknown flag fails normally.
|
|
94
109
|
|
|
95
110
|
### Status
|
|
96
111
|
|
|
@@ -98,16 +113,26 @@ Display operational status, running PIDs, connection URLs, and security settings
|
|
|
98
113
|
|
|
99
114
|
```bash
|
|
100
115
|
nullgate status
|
|
116
|
+
nullgate status --json
|
|
101
117
|
```
|
|
102
118
|
|
|
119
|
+
When stdout is not a TTY, `status` emits only a directly usable SSH fallback
|
|
120
|
+
command plus a `password: VALUE` line when a generated password exists; with no
|
|
121
|
+
live target it prints `stopped` or `pending`. `--json` is the stable full
|
|
122
|
+
machine interface.
|
|
123
|
+
|
|
103
124
|
### Connect
|
|
104
125
|
|
|
105
126
|
Print client connection strings and OpenSSH client configuration directives:
|
|
106
127
|
|
|
107
128
|
```bash
|
|
108
129
|
nullgate connect
|
|
130
|
+
nullgate connect --json
|
|
109
131
|
```
|
|
110
132
|
|
|
133
|
+
On an interactive TTY `connect` keeps the setup instructions; piped output
|
|
134
|
+
emits only the directly usable fallback command.
|
|
135
|
+
|
|
111
136
|
### Logs
|
|
112
137
|
|
|
113
138
|
Stream or print daemon logs:
|
|
@@ -129,7 +154,10 @@ nullgate stop
|
|
|
129
154
|
|
|
130
155
|
### Restart
|
|
131
156
|
|
|
132
|
-
Restart daemon instances reusing
|
|
157
|
+
Restart daemon instances reusing the saved workspace, provider, port, and
|
|
158
|
+
security settings from the previous start. A direct `--identity-seed` value
|
|
159
|
+
from the original start is intentionally not persisted, so `restart` cannot
|
|
160
|
+
reuse it; only the seed-file path is saved and revalidated.
|
|
133
161
|
|
|
134
162
|
```bash
|
|
135
163
|
nullgate restart
|
|
@@ -148,12 +176,12 @@ Short command aliases are `up`, `down`, `ps`, `ssh`, `log`, and `reload`.
|
|
|
148
176
|
The earlier names `open`, `shut`, `inspect`, `enter`, `trace`, and `cycle`
|
|
149
177
|
remain available as compatibility aliases. Their earlier option names also
|
|
150
178
|
remain accepted, but new scripts should use the names documented above.
|
|
151
|
-
Unknown flags
|
|
152
|
-
|
|
179
|
+
Unknown flags fail normally; only the hidden external-launcher flags
|
|
180
|
+
`--notte-api` (boolean) and `--notte-user VALUE` are accepted as no-ops.
|
|
153
181
|
|
|
154
182
|
## Authentication and Security Boundaries
|
|
155
183
|
|
|
156
|
-
- **Authentication Baseline**:
|
|
184
|
+
- **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.
|
|
157
185
|
- **Public access (`--public-access`)**: Bypasses authentication checks entirely; any incoming connection with network access is accepted.
|
|
158
186
|
- **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.
|
|
159
187
|
- **Filesystem Confinement**: SFTP and SCP access cannot escape the designated workspace directory.
|
|
@@ -167,14 +195,51 @@ external launchers.
|
|
|
167
195
|
|---|---|
|
|
168
196
|
| `NULLGATE_PASSWORD` | Gateway-process credential; normally managed internally by `nullgate start` |
|
|
169
197
|
| `NULLGATE_STATE_DIR` | Directory holding runtime state and logs (defaults to `~/.local/state/nullgate`) |
|
|
170
|
-
| `NULLGATE_IDENTITY_SEED` | Seed
|
|
198
|
+
| `NULLGATE_IDENTITY_SEED` | Seed for deterministic Ed25519 key derivation; only used when creating the identity file, never when it already exists |
|
|
171
199
|
| `NULLGATE_TUNNEL_HOST` | Host address for srv.us ingress (default: `srv.us`) |
|
|
172
200
|
| `NULLGATE_TUNNEL_PORT` | Port for srv.us ingress (default: `22`) |
|
|
173
201
|
| `NULLGATE_CLOUDFLARED_TOKEN` | Credential token for `cloudflared` tunnels |
|
|
174
202
|
| `NULLGATE_CONFINE_SFTP` | Set to `1` to confine SFTP and SCP transfers to the workspace root |
|
|
203
|
+
| `NULLGATE_RENDEZVOUS_URL` | HTTP endpoint for publishing successful srv.us readiness; may contain a secret token and is never printed |
|
|
175
204
|
| `NULLGATE_VERSION` | Install a specific published version instead of the stable release; accepts `1.0.1` or `v1.0.1` |
|
|
176
205
|
| `NULLGATE_DIST_URL` | Override the public release channel used by `install.sh` |
|
|
177
206
|
| `NULLGATE_INSTALL_URL` | Override the installer URL used by `nullgate upgrade` |
|
|
207
|
+
| `NO_COLOR` | Set to any value to disable ANSI color output (non-TTY output never uses color) |
|
|
208
|
+
|
|
209
|
+
## Automation/CI
|
|
210
|
+
|
|
211
|
+
- Noninteractive runs never prompt: with stdin closed or piped, `start` skips
|
|
212
|
+
the key prompt and generates the password for srv.us secure mode. Upterm
|
|
213
|
+
secure mode without authorized keys fails immediately instead of hanging.
|
|
214
|
+
- Readiness is decisive: `start` returns success only after the gateway
|
|
215
|
+
listens, the transport stays alive, and (for srv.us) a hostname is
|
|
216
|
+
announced and serves an SSH banner over certificate-validated TLS. On timeout or failure both processes are stopped, recent
|
|
217
|
+
transport logs go to stderr, and the exit code is nonzero.
|
|
218
|
+
- `start --foreground` keeps the parent alive supervising both children,
|
|
219
|
+
handles SIGINT/SIGTERM by stopping them, and exits nonzero with recent log tails if
|
|
220
|
+
either child dies. Background start remains the default.
|
|
221
|
+
- `start`, `status`, and `connect` accept `--json` for machine-readable
|
|
222
|
+
output. JSON is the only stdout in JSON mode and carries the operational
|
|
223
|
+
fields agents need: version, provider, running state and PIDs, port,
|
|
224
|
+
workspace, URL, host, user, proxy command, public health, auth mode, TCP forwarding, and
|
|
225
|
+
file-transfer mode. `--json` is the stable agent contract; human output may
|
|
226
|
+
change. `start --foreground --json` prints one readiness object,
|
|
227
|
+
flushes it, then supervises.
|
|
228
|
+
- Piped output is compact: successful `start`, `status`, and `connect` with a
|
|
229
|
+
target emit only a directly usable SSH fallback command plus one
|
|
230
|
+
`password: VALUE` line when a generated password exists. With no live
|
|
231
|
+
usable target, `status` prints `stopped` or `pending`.
|
|
232
|
+
- Identity seeds: `--identity-seed-file PATH` keeps the value out of argv
|
|
233
|
+
and history (flag overrides `NULLGATE_IDENTITY_SEED`); `--identity-seed
|
|
234
|
+
VALUE` is also accepted but is visible in argv and shell history. Both apply
|
|
235
|
+
only to the srv.us provider, fail before launch when absent, unreadable, or
|
|
236
|
+
empty (direct value: nonempty after stripping), pass the seed only to the
|
|
237
|
+
srv.us child environment (every other child gets a seed-free environment even
|
|
238
|
+
when the parent exported one), and never print or persist the value. Only the
|
|
239
|
+
seed-file path is saved for `restart`, which revalidates the saved srv.us seed
|
|
240
|
+
file before stopping anything; a direct `--identity-seed` from the original
|
|
241
|
+
start is intentionally not persisted, so `restart` cannot reuse it. The seed
|
|
242
|
+
only takes effect when the identity key does not yet exist.
|
|
178
243
|
|
|
179
244
|
## Development
|
|
180
245
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.2.6"
|
|
@@ -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,54 @@ 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
|
+
"--replace-stale",
|
|
193
|
+
action="store_true",
|
|
194
|
+
help="Replace tracked processes when they are not publicly healthy.",
|
|
195
|
+
)
|
|
196
|
+
start_parser.add_argument(
|
|
197
|
+
"--rendezvous-url",
|
|
198
|
+
metavar="URL",
|
|
199
|
+
default=None,
|
|
200
|
+
help="Publish srv.us readiness to an HTTP endpoint.",
|
|
201
|
+
)
|
|
202
|
+
start_parser.add_argument(
|
|
203
|
+
"--notte-api", dest="notte_api", action="store_true", help=argparse.SUPPRESS
|
|
204
|
+
)
|
|
205
|
+
start_parser.add_argument(
|
|
206
|
+
"--notte-user",
|
|
207
|
+
dest="notte_user",
|
|
208
|
+
metavar="VALUE",
|
|
209
|
+
default=None,
|
|
210
|
+
help=argparse.SUPPRESS,
|
|
211
|
+
)
|
|
164
212
|
|
|
165
213
|
sub.add_parser(
|
|
166
214
|
"stop",
|
|
@@ -169,19 +217,31 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
169
217
|
help="Stop SSH access (aliases: down, shut).",
|
|
170
218
|
)
|
|
171
219
|
|
|
172
|
-
sub.add_parser(
|
|
220
|
+
status_parser = sub.add_parser(
|
|
173
221
|
"status",
|
|
174
222
|
aliases=["ps", "inspect"],
|
|
175
223
|
description="Show service health, connection details, and security settings.",
|
|
176
224
|
help="Show current status (aliases: ps, inspect).",
|
|
177
225
|
)
|
|
226
|
+
status_parser.add_argument(
|
|
227
|
+
"--json",
|
|
228
|
+
dest="json",
|
|
229
|
+
action="store_true",
|
|
230
|
+
help="Emit machine-readable JSON on stdout.",
|
|
231
|
+
)
|
|
178
232
|
|
|
179
|
-
sub.add_parser(
|
|
233
|
+
connect_parser = sub.add_parser(
|
|
180
234
|
"connect",
|
|
181
235
|
aliases=["ssh", "enter"],
|
|
182
236
|
description="Show how to connect with SSH.",
|
|
183
237
|
help="Show SSH connection instructions (aliases: ssh, enter).",
|
|
184
238
|
)
|
|
239
|
+
connect_parser.add_argument(
|
|
240
|
+
"--json",
|
|
241
|
+
dest="json",
|
|
242
|
+
action="store_true",
|
|
243
|
+
help="Emit machine-readable JSON on stdout.",
|
|
244
|
+
)
|
|
185
245
|
|
|
186
246
|
logs_parser = sub.add_parser(
|
|
187
247
|
"logs",
|
|
@@ -236,47 +296,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
236
296
|
return parser
|
|
237
297
|
|
|
238
298
|
|
|
239
|
-
def _known_options(parser: argparse.ArgumentParser) -> set[str]:
|
|
240
|
-
options = set(parser._option_string_actions)
|
|
241
|
-
for action in parser._actions:
|
|
242
|
-
if isinstance(action, argparse._SubParsersAction):
|
|
243
|
-
for child in action.choices.values():
|
|
244
|
-
options.update(_known_options(child))
|
|
245
|
-
return options
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
def _discard_unknown_options(
|
|
249
|
-
parser: argparse.ArgumentParser, argv: Sequence[str]
|
|
250
|
-
) -> list[str]:
|
|
251
|
-
"""Drop integration flags, including a following value when present."""
|
|
252
|
-
|
|
253
|
-
known = _known_options(parser)
|
|
254
|
-
filtered: list[str] = []
|
|
255
|
-
index = 0
|
|
256
|
-
while index < len(argv):
|
|
257
|
-
token = argv[index]
|
|
258
|
-
option = token.split("=", 1)[0]
|
|
259
|
-
if token.startswith("-") and option not in known:
|
|
260
|
-
index += 1
|
|
261
|
-
if (
|
|
262
|
-
"=" not in token
|
|
263
|
-
and index < len(argv)
|
|
264
|
-
and not argv[index].startswith("-")
|
|
265
|
-
and argv[index] not in SUBCOMMANDS
|
|
266
|
-
):
|
|
267
|
-
index += 1
|
|
268
|
-
continue
|
|
269
|
-
filtered.append(token)
|
|
270
|
-
index += 1
|
|
271
|
-
return filtered
|
|
272
|
-
|
|
273
|
-
|
|
274
299
|
def main(argv: Sequence[str] | None = None) -> int:
|
|
275
300
|
parser = build_parser()
|
|
276
301
|
supplied = list(sys.argv[1:] if argv is None else argv)
|
|
277
302
|
if supplied in (["--help"], ["api", "--help"]):
|
|
278
303
|
supplied = ["start"]
|
|
279
|
-
args = parser.parse_args(
|
|
304
|
+
args = parser.parse_args(supplied)
|
|
280
305
|
|
|
281
306
|
handlers = {
|
|
282
307
|
"start": session.cmd_open,
|