nullgate 1.2.4__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.4/src/nullgate.egg-info → nullgate-1.2.5}/PKG-INFO +74 -12
- {nullgate-1.2.4 → nullgate-1.2.5}/README.md +73 -11
- nullgate-1.2.5/src/nullgate/__init__.py +1 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/commands.py +53 -39
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/session.py +282 -29
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/transports.py +46 -20
- {nullgate-1.2.4 → nullgate-1.2.5/src/nullgate.egg-info}/PKG-INFO +74 -12
- nullgate-1.2.5/tests/test_commands.py +2169 -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.5}/LICENSE +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/pyproject.toml +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/setup.cfg +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/account.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/bridge.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/client_config.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/gateway.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/ingress.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/runtime.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/wsroute.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate.egg-info/SOURCES.txt +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate.egg-info/dependency_links.txt +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate.egg-info/entry_points.txt +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate.egg-info/requires.txt +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate.egg-info/top_level.txt +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/tests/test_account.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/tests/test_bridge.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/tests/test_gateway.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/tests/test_ingress.py +0 -0
- {nullgate-1.2.4 → nullgate-1.2.5}/tests/test_install.py +0 -0
- {nullgate-1.2.4 → 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
|
|
@@ -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,22 @@ 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
|
+
|
|
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.
|
|
106
119
|
|
|
107
120
|
### Status
|
|
108
121
|
|
|
@@ -110,16 +123,26 @@ Display operational status, running PIDs, connection URLs, and security settings
|
|
|
110
123
|
|
|
111
124
|
```bash
|
|
112
125
|
nullgate status
|
|
126
|
+
nullgate status --json
|
|
113
127
|
```
|
|
114
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
|
+
|
|
115
134
|
### Connect
|
|
116
135
|
|
|
117
136
|
Print client connection strings and OpenSSH client configuration directives:
|
|
118
137
|
|
|
119
138
|
```bash
|
|
120
139
|
nullgate connect
|
|
140
|
+
nullgate connect --json
|
|
121
141
|
```
|
|
122
142
|
|
|
143
|
+
On an interactive TTY `connect` keeps the setup instructions; piped output
|
|
144
|
+
emits only the directly usable fallback command.
|
|
145
|
+
|
|
123
146
|
### Logs
|
|
124
147
|
|
|
125
148
|
Stream or print daemon logs:
|
|
@@ -141,7 +164,10 @@ nullgate stop
|
|
|
141
164
|
|
|
142
165
|
### Restart
|
|
143
166
|
|
|
144
|
-
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.
|
|
145
171
|
|
|
146
172
|
```bash
|
|
147
173
|
nullgate restart
|
|
@@ -160,12 +186,12 @@ Short command aliases are `up`, `down`, `ps`, `ssh`, `log`, and `reload`.
|
|
|
160
186
|
The earlier names `open`, `shut`, `inspect`, `enter`, `trace`, and `cycle`
|
|
161
187
|
remain available as compatibility aliases. Their earlier option names also
|
|
162
188
|
remain accepted, but new scripts should use the names documented above.
|
|
163
|
-
Unknown flags
|
|
164
|
-
|
|
189
|
+
Unknown flags fail normally; only the hidden external-launcher flags
|
|
190
|
+
`--notte-api` (boolean) and `--notte-user VALUE` are accepted as no-ops.
|
|
165
191
|
|
|
166
192
|
## Authentication and Security Boundaries
|
|
167
193
|
|
|
168
|
-
- **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.
|
|
169
195
|
- **Public access (`--public-access`)**: Bypasses authentication checks entirely; any incoming connection with network access is accepted.
|
|
170
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.
|
|
171
197
|
- **Filesystem Confinement**: SFTP and SCP access cannot escape the designated workspace directory.
|
|
@@ -179,7 +205,7 @@ external launchers.
|
|
|
179
205
|
|---|---|
|
|
180
206
|
| `NULLGATE_PASSWORD` | Gateway-process credential; normally managed internally by `nullgate start` |
|
|
181
207
|
| `NULLGATE_STATE_DIR` | Directory holding runtime state and logs (defaults to `~/.local/state/nullgate`) |
|
|
182
|
-
| `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 |
|
|
183
209
|
| `NULLGATE_TUNNEL_HOST` | Host address for srv.us ingress (default: `srv.us`) |
|
|
184
210
|
| `NULLGATE_TUNNEL_PORT` | Port for srv.us ingress (default: `22`) |
|
|
185
211
|
| `NULLGATE_CLOUDFLARED_TOKEN` | Credential token for `cloudflared` tunnels |
|
|
@@ -187,6 +213,42 @@ external launchers.
|
|
|
187
213
|
| `NULLGATE_VERSION` | Install a specific published version instead of the stable release; accepts `1.0.1` or `v1.0.1` |
|
|
188
214
|
| `NULLGATE_DIST_URL` | Override the public release channel used by `install.sh` |
|
|
189
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.
|
|
190
252
|
|
|
191
253
|
## Development
|
|
192
254
|
|
|
@@ -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,22 @@ 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
|
+
|
|
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.
|
|
94
107
|
|
|
95
108
|
### Status
|
|
96
109
|
|
|
@@ -98,16 +111,26 @@ Display operational status, running PIDs, connection URLs, and security settings
|
|
|
98
111
|
|
|
99
112
|
```bash
|
|
100
113
|
nullgate status
|
|
114
|
+
nullgate status --json
|
|
101
115
|
```
|
|
102
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
|
+
|
|
103
122
|
### Connect
|
|
104
123
|
|
|
105
124
|
Print client connection strings and OpenSSH client configuration directives:
|
|
106
125
|
|
|
107
126
|
```bash
|
|
108
127
|
nullgate connect
|
|
128
|
+
nullgate connect --json
|
|
109
129
|
```
|
|
110
130
|
|
|
131
|
+
On an interactive TTY `connect` keeps the setup instructions; piped output
|
|
132
|
+
emits only the directly usable fallback command.
|
|
133
|
+
|
|
111
134
|
### Logs
|
|
112
135
|
|
|
113
136
|
Stream or print daemon logs:
|
|
@@ -129,7 +152,10 @@ nullgate stop
|
|
|
129
152
|
|
|
130
153
|
### Restart
|
|
131
154
|
|
|
132
|
-
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.
|
|
133
159
|
|
|
134
160
|
```bash
|
|
135
161
|
nullgate restart
|
|
@@ -148,12 +174,12 @@ Short command aliases are `up`, `down`, `ps`, `ssh`, `log`, and `reload`.
|
|
|
148
174
|
The earlier names `open`, `shut`, `inspect`, `enter`, `trace`, and `cycle`
|
|
149
175
|
remain available as compatibility aliases. Their earlier option names also
|
|
150
176
|
remain accepted, but new scripts should use the names documented above.
|
|
151
|
-
Unknown flags
|
|
152
|
-
|
|
177
|
+
Unknown flags fail normally; only the hidden external-launcher flags
|
|
178
|
+
`--notte-api` (boolean) and `--notte-user VALUE` are accepted as no-ops.
|
|
153
179
|
|
|
154
180
|
## Authentication and Security Boundaries
|
|
155
181
|
|
|
156
|
-
- **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.
|
|
157
183
|
- **Public access (`--public-access`)**: Bypasses authentication checks entirely; any incoming connection with network access is accepted.
|
|
158
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.
|
|
159
185
|
- **Filesystem Confinement**: SFTP and SCP access cannot escape the designated workspace directory.
|
|
@@ -167,7 +193,7 @@ external launchers.
|
|
|
167
193
|
|---|---|
|
|
168
194
|
| `NULLGATE_PASSWORD` | Gateway-process credential; normally managed internally by `nullgate start` |
|
|
169
195
|
| `NULLGATE_STATE_DIR` | Directory holding runtime state and logs (defaults to `~/.local/state/nullgate`) |
|
|
170
|
-
| `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 |
|
|
171
197
|
| `NULLGATE_TUNNEL_HOST` | Host address for srv.us ingress (default: `srv.us`) |
|
|
172
198
|
| `NULLGATE_TUNNEL_PORT` | Port for srv.us ingress (default: `22`) |
|
|
173
199
|
| `NULLGATE_CLOUDFLARED_TOKEN` | Credential token for `cloudflared` tunnels |
|
|
@@ -175,6 +201,42 @@ external launchers.
|
|
|
175
201
|
| `NULLGATE_VERSION` | Install a specific published version instead of the stable release; accepts `1.0.1` or `v1.0.1` |
|
|
176
202
|
| `NULLGATE_DIST_URL` | Override the public release channel used by `install.sh` |
|
|
177
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.
|
|
178
240
|
|
|
179
241
|
## Development
|
|
180
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",
|
|
@@ -236,47 +285,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
236
285
|
return parser
|
|
237
286
|
|
|
238
287
|
|
|
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
288
|
def main(argv: Sequence[str] | None = None) -> int:
|
|
275
289
|
parser = build_parser()
|
|
276
290
|
supplied = list(sys.argv[1:] if argv is None else argv)
|
|
277
291
|
if supplied in (["--help"], ["api", "--help"]):
|
|
278
292
|
supplied = ["start"]
|
|
279
|
-
args = parser.parse_args(
|
|
293
|
+
args = parser.parse_args(supplied)
|
|
280
294
|
|
|
281
295
|
handlers = {
|
|
282
296
|
"start": session.cmd_open,
|