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.
Files changed (31) hide show
  1. {nullgate-1.2.4/src/nullgate.egg-info → nullgate-1.2.5}/PKG-INFO +74 -12
  2. {nullgate-1.2.4 → nullgate-1.2.5}/README.md +73 -11
  3. nullgate-1.2.5/src/nullgate/__init__.py +1 -0
  4. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/commands.py +53 -39
  5. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/session.py +282 -29
  6. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/transports.py +46 -20
  7. {nullgate-1.2.4 → nullgate-1.2.5/src/nullgate.egg-info}/PKG-INFO +74 -12
  8. nullgate-1.2.5/tests/test_commands.py +2169 -0
  9. nullgate-1.2.4/src/nullgate/__init__.py +0 -1
  10. nullgate-1.2.4/tests/test_commands.py +0 -770
  11. {nullgate-1.2.4 → nullgate-1.2.5}/LICENSE +0 -0
  12. {nullgate-1.2.4 → nullgate-1.2.5}/pyproject.toml +0 -0
  13. {nullgate-1.2.4 → nullgate-1.2.5}/setup.cfg +0 -0
  14. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/account.py +0 -0
  15. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/bridge.py +0 -0
  16. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/client_config.py +0 -0
  17. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/gateway.py +0 -0
  18. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/ingress.py +0 -0
  19. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/runtime.py +0 -0
  20. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate/wsroute.py +0 -0
  21. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate.egg-info/SOURCES.txt +0 -0
  22. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate.egg-info/dependency_links.txt +0 -0
  23. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate.egg-info/entry_points.txt +0 -0
  24. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate.egg-info/requires.txt +0 -0
  25. {nullgate-1.2.4 → nullgate-1.2.5}/src/nullgate.egg-info/top_level.txt +0 -0
  26. {nullgate-1.2.4 → nullgate-1.2.5}/tests/test_account.py +0 -0
  27. {nullgate-1.2.4 → nullgate-1.2.5}/tests/test_bridge.py +0 -0
  28. {nullgate-1.2.4 → nullgate-1.2.5}/tests/test_gateway.py +0 -0
  29. {nullgate-1.2.4 → nullgate-1.2.5}/tests/test_ingress.py +0 -0
  30. {nullgate-1.2.4 → nullgate-1.2.5}/tests/test_install.py +0 -0
  31. {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.4
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 allows connections without credentials by default. Use
40
- `--no-public-access` to require an authorized SSH key or generated password.
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
- Launch the gateway service and ingress transport in the background:
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
- - `--public-access`: Allow connections without credentials. Enabled by default and unsafe on public endpoints.
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`: Enable SSH TCP tunneling (`ssh -L`).
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 active or saved workspace settings:
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 and their optional values are ignored for compatibility with
164
- external launchers.
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**: Public access is enabled by default. Pass `--no-public-access` to require authorized SSH keys from `~/.ssh/authorized_keys` or a high-entropy secret created in the runtime directory.
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 value used for deterministic Ed25519 key derivation |
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 allows connections without credentials by default. Use
28
- `--no-public-access` to require an authorized SSH key or generated password.
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
- Launch the gateway service and ingress transport in the background:
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
- - `--public-access`: Allow connections without credentials. Enabled by default and unsafe on public endpoints.
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`: Enable SSH TCP tunneling (`ssh -L`).
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 active or saved workspace settings:
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 and their optional values are ignored for compatibility with
152
- external launchers.
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**: Public access is enabled by default. Pass `--no-public-access` to require authorized SSH keys from `~/.ssh/authorized_keys` or a high-entropy secret created in the runtime directory.
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 value used for deterministic Ed25519 key derivation |
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(_discard_unknown_options(parser, supplied))
293
+ args = parser.parse_args(supplied)
280
294
 
281
295
  handlers = {
282
296
  "start": session.cmd_open,