nullgate 1.2.0__tar.gz → 1.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {nullgate-1.2.0/src/nullgate.egg-info → nullgate-1.2.1}/PKG-INFO +39 -7
  2. {nullgate-1.2.0 → nullgate-1.2.1}/README.md +38 -6
  3. nullgate-1.2.1/src/nullgate/__init__.py +1 -0
  4. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate/commands.py +41 -12
  5. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate/session.py +11 -2
  6. {nullgate-1.2.0 → nullgate-1.2.1/src/nullgate.egg-info}/PKG-INFO +39 -7
  7. {nullgate-1.2.0 → nullgate-1.2.1}/tests/test_commands.py +49 -0
  8. nullgate-1.2.0/src/nullgate/__init__.py +0 -1
  9. {nullgate-1.2.0 → nullgate-1.2.1}/LICENSE +0 -0
  10. {nullgate-1.2.0 → nullgate-1.2.1}/pyproject.toml +0 -0
  11. {nullgate-1.2.0 → nullgate-1.2.1}/setup.cfg +0 -0
  12. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate/account.py +0 -0
  13. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate/bridge.py +0 -0
  14. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate/client_config.py +0 -0
  15. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate/gateway.py +0 -0
  16. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate/ingress.py +0 -0
  17. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate/runtime.py +0 -0
  18. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate/transports.py +0 -0
  19. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate/wsroute.py +0 -0
  20. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate.egg-info/SOURCES.txt +0 -0
  21. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate.egg-info/dependency_links.txt +0 -0
  22. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate.egg-info/entry_points.txt +0 -0
  23. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate.egg-info/requires.txt +0 -0
  24. {nullgate-1.2.0 → nullgate-1.2.1}/src/nullgate.egg-info/top_level.txt +0 -0
  25. {nullgate-1.2.0 → nullgate-1.2.1}/tests/test_account.py +0 -0
  26. {nullgate-1.2.0 → nullgate-1.2.1}/tests/test_bridge.py +0 -0
  27. {nullgate-1.2.0 → nullgate-1.2.1}/tests/test_gateway.py +0 -0
  28. {nullgate-1.2.0 → nullgate-1.2.1}/tests/test_ingress.py +0 -0
  29. {nullgate-1.2.0 → nullgate-1.2.1}/tests/test_install.py +0 -0
  30. {nullgate-1.2.0 → nullgate-1.2.1}/tests/test_wsroute.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nullgate
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: Disposable SSH gateway into confined directory workspaces
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -14,6 +14,32 @@ Dynamic: license-file
14
14
 
15
15
  Disposable SSH gateway into confined directory workspaces for remote containers, ephemeral developer boxes, CI nodes, and cloud instances.
16
16
 
17
+ ## Quick start
18
+
19
+ Run Nullgate directly from PyPI without installing it first:
20
+
21
+ ```bash
22
+ # Share the current directory over the default Upterm provider
23
+ uvx nullgate start
24
+
25
+ # Share a specific workspace
26
+ uvx nullgate start /workspace
27
+
28
+ # Compact form: workspace, SSH port, srv.us slot, provider
29
+ uvx nullgate start /workspace 8022 1 -t srvus
30
+ ```
31
+
32
+ Then check the endpoint and print the SSH connection setup:
33
+
34
+ ```bash
35
+ uvx nullgate status
36
+ uvx nullgate connect
37
+ ```
38
+
39
+ Nullgate uses authorized SSH keys by default. Upterm needs a key in
40
+ `~/.ssh/authorized_keys`; use `--public-access` only for an intentionally public
41
+ temporary endpoint.
42
+
17
43
  ## Features
18
44
 
19
45
  - **Ingress Transports**: Publish endpoints via Upterm WebSocket relays (default), srv.us reverse tunnels, Cloudflare Worker relays, or Cloudflare Argo (`cloudflared`) tunnels.
@@ -55,6 +81,9 @@ nullgate start
55
81
  # Custom path, port, and slot
56
82
  nullgate start /workspace --ssh-port 4822 --tunnel-slot 1
57
83
 
84
+ # The same values in compact positional form
85
+ nullgate start /workspace 4822 1
86
+
58
87
  # Select specific transport provider
59
88
  nullgate start . --provider upterm
60
89
  nullgate start . --provider srvus
@@ -63,9 +92,11 @@ nullgate start . --provider cloudflared --public-hostname workspace.example.com
63
92
  ```
64
93
 
65
94
  Options:
66
- - `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `upterm`.
67
- - `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
68
- - `--public-hostname`: Public hostname used with `cloudflared`.
95
+ - `-p`, `--ssh-port`: Local SSH server port.
96
+ - `-s`, `--tunnel-slot`: srv.us tunnel slot.
97
+ - `-t`, `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `upterm`.
98
+ - `-e`, `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
99
+ - `-H`, `--public-hostname`: Public hostname used with `cloudflared`.
69
100
  - `--cloudflare-token`: Cloudflare tunnel credential, or set `NULLGATE_CLOUDFLARED_TOKEN`.
70
101
  - `--public-access`: Allow connections without credentials. This is unsafe on public endpoints.
71
102
  - `--no-public-access`: Require authentication.
@@ -126,9 +157,10 @@ nullgate upgrade
126
157
  nullgate upgrade --version 1.0.1
127
158
  ```
128
159
 
129
- The earlier command names `open`, `shut`, `inspect`, `enter`, `trace`, and
130
- `cycle` remain available as compatibility aliases. Their earlier option names
131
- also remain accepted, but new scripts should use the names documented above.
160
+ Short command aliases are `up`, `down`, `ps`, `ssh`, `log`, and `reload`.
161
+ The earlier names `open`, `shut`, `inspect`, `enter`, `trace`, and `cycle`
162
+ remain available as compatibility aliases. Their earlier option names also
163
+ remain accepted, but new scripts should use the names documented above.
132
164
 
133
165
  ## Authentication and Security Boundaries
134
166
 
@@ -2,6 +2,32 @@
2
2
 
3
3
  Disposable SSH gateway into confined directory workspaces for remote containers, ephemeral developer boxes, CI nodes, and cloud instances.
4
4
 
5
+ ## Quick start
6
+
7
+ Run Nullgate directly from PyPI without installing it first:
8
+
9
+ ```bash
10
+ # Share the current directory over the default Upterm provider
11
+ uvx nullgate start
12
+
13
+ # Share a specific workspace
14
+ uvx nullgate start /workspace
15
+
16
+ # Compact form: workspace, SSH port, srv.us slot, provider
17
+ uvx nullgate start /workspace 8022 1 -t srvus
18
+ ```
19
+
20
+ Then check the endpoint and print the SSH connection setup:
21
+
22
+ ```bash
23
+ uvx nullgate status
24
+ uvx nullgate connect
25
+ ```
26
+
27
+ Nullgate uses authorized SSH keys by default. Upterm needs a key in
28
+ `~/.ssh/authorized_keys`; use `--public-access` only for an intentionally public
29
+ temporary endpoint.
30
+
5
31
  ## Features
6
32
 
7
33
  - **Ingress Transports**: Publish endpoints via Upterm WebSocket relays (default), srv.us reverse tunnels, Cloudflare Worker relays, or Cloudflare Argo (`cloudflared`) tunnels.
@@ -43,6 +69,9 @@ nullgate start
43
69
  # Custom path, port, and slot
44
70
  nullgate start /workspace --ssh-port 4822 --tunnel-slot 1
45
71
 
72
+ # The same values in compact positional form
73
+ nullgate start /workspace 4822 1
74
+
46
75
  # Select specific transport provider
47
76
  nullgate start . --provider upterm
48
77
  nullgate start . --provider srvus
@@ -51,9 +80,11 @@ nullgate start . --provider cloudflared --public-hostname workspace.example.com
51
80
  ```
52
81
 
53
82
  Options:
54
- - `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `upterm`.
55
- - `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
56
- - `--public-hostname`: Public hostname used with `cloudflared`.
83
+ - `-p`, `--ssh-port`: Local SSH server port.
84
+ - `-s`, `--tunnel-slot`: srv.us tunnel slot.
85
+ - `-t`, `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `upterm`.
86
+ - `-e`, `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
87
+ - `-H`, `--public-hostname`: Public hostname used with `cloudflared`.
57
88
  - `--cloudflare-token`: Cloudflare tunnel credential, or set `NULLGATE_CLOUDFLARED_TOKEN`.
58
89
  - `--public-access`: Allow connections without credentials. This is unsafe on public endpoints.
59
90
  - `--no-public-access`: Require authentication.
@@ -114,9 +145,10 @@ nullgate upgrade
114
145
  nullgate upgrade --version 1.0.1
115
146
  ```
116
147
 
117
- The earlier command names `open`, `shut`, `inspect`, `enter`, `trace`, and
118
- `cycle` remain available as compatibility aliases. Their earlier option names
119
- also remain accepted, but new scripts should use the names documented above.
148
+ Short command aliases are `up`, `down`, `ps`, `ssh`, `log`, and `reload`.
149
+ The earlier names `open`, `shut`, `inspect`, `enter`, `trace`, and `cycle`
150
+ remain available as compatibility aliases. Their earlier option names also
151
+ remain accepted, but new scripts should use the names documented above.
120
152
 
121
153
  ## Authentication and Security Boundaries
122
154
 
@@ -0,0 +1 @@
1
+ __version__ = "1.2.1"
@@ -10,11 +10,17 @@ from nullgate import session, transports
10
10
 
11
11
  SUBCOMMANDS = (
12
12
  "start",
13
+ "up",
13
14
  "stop",
15
+ "down",
14
16
  "status",
17
+ "ps",
15
18
  "connect",
19
+ "ssh",
16
20
  "logs",
21
+ "log",
17
22
  "restart",
23
+ "reload",
18
24
  "upgrade",
19
25
  "open",
20
26
  "shut",
@@ -40,9 +46,9 @@ def build_parser() -> argparse.ArgumentParser:
40
46
 
41
47
  start_parser = sub.add_parser(
42
48
  "start",
43
- aliases=["open"],
49
+ aliases=["up", "open"],
44
50
  description="Start SSH access to a workspace.",
45
- help="Start SSH access to a workspace (alias: open).",
51
+ help="Start SSH access to a workspace (aliases: up, open).",
46
52
  )
47
53
  start_parser.add_argument(
48
54
  "workspace",
@@ -50,6 +56,19 @@ def build_parser() -> argparse.ArgumentParser:
50
56
  help="Directory to make available (default: current directory).",
51
57
  )
52
58
  start_parser.add_argument(
59
+ "port_arg",
60
+ nargs="?",
61
+ type=int,
62
+ help="Local SSH server port (shorthand positional).",
63
+ )
64
+ start_parser.add_argument(
65
+ "slot_arg",
66
+ nargs="?",
67
+ type=int,
68
+ help="srv.us tunnel slot (shorthand positional).",
69
+ )
70
+ start_parser.add_argument(
71
+ "-p",
53
72
  "--ssh-port",
54
73
  dest="port",
55
74
  type=int,
@@ -58,6 +77,7 @@ def build_parser() -> argparse.ArgumentParser:
58
77
  )
59
78
  start_parser.add_argument("--port", dest="port", type=int, help=argparse.SUPPRESS)
60
79
  start_parser.add_argument(
80
+ "-s",
61
81
  "--tunnel-slot",
62
82
  dest="slot",
63
83
  type=int,
@@ -66,6 +86,7 @@ def build_parser() -> argparse.ArgumentParser:
66
86
  )
67
87
  start_parser.add_argument("--slot", dest="slot", type=int, help=argparse.SUPPRESS)
68
88
  start_parser.add_argument(
89
+ "-t",
69
90
  "--provider",
70
91
  dest="transport",
71
92
  choices=transports.VALID_TRANSPORTS,
@@ -121,12 +142,14 @@ def build_parser() -> argparse.ArgumentParser:
121
142
  help=argparse.SUPPRESS,
122
143
  )
123
144
  start_parser.add_argument(
145
+ "-e",
124
146
  "--relay-url",
125
147
  dest="endpoint",
126
148
  help="WebSocket relay URL (for upterm or cloudflare providers).",
127
149
  )
128
150
  start_parser.add_argument("--endpoint", dest="endpoint", help=argparse.SUPPRESS)
129
151
  start_parser.add_argument(
152
+ "-H",
130
153
  "--public-hostname",
131
154
  dest="hostname",
132
155
  help="Public hostname (for the cloudflared provider).",
@@ -141,30 +164,30 @@ def build_parser() -> argparse.ArgumentParser:
141
164
 
142
165
  sub.add_parser(
143
166
  "stop",
144
- aliases=["shut"],
167
+ aliases=["down", "shut"],
145
168
  description="Stop SSH access and its connection provider.",
146
- help="Stop SSH access (alias: shut).",
169
+ help="Stop SSH access (aliases: down, shut).",
147
170
  )
148
171
 
149
172
  sub.add_parser(
150
173
  "status",
151
- aliases=["inspect"],
174
+ aliases=["ps", "inspect"],
152
175
  description="Show service health, connection details, and security settings.",
153
- help="Show current status (alias: inspect).",
176
+ help="Show current status (aliases: ps, inspect).",
154
177
  )
155
178
 
156
179
  sub.add_parser(
157
180
  "connect",
158
- aliases=["enter"],
181
+ aliases=["ssh", "enter"],
159
182
  description="Show how to connect with SSH.",
160
- help="Show SSH connection instructions (alias: enter).",
183
+ help="Show SSH connection instructions (aliases: ssh, enter).",
161
184
  )
162
185
 
163
186
  logs_parser = sub.add_parser(
164
187
  "logs",
165
- aliases=["trace"],
188
+ aliases=["log", "trace"],
166
189
  description="View or follow service logs.",
167
- help="View or follow service logs (alias: trace).",
190
+ help="View or follow service logs (aliases: log, trace).",
168
191
  )
169
192
  logs_parser.add_argument(
170
193
  "target",
@@ -183,9 +206,9 @@ def build_parser() -> argparse.ArgumentParser:
183
206
 
184
207
  sub.add_parser(
185
208
  "restart",
186
- aliases=["cycle"],
209
+ aliases=["reload", "cycle"],
187
210
  description="Restart SSH access using the saved settings.",
188
- help="Restart using saved settings (alias: cycle).",
211
+ help="Restart using saved settings (aliases: reload, cycle).",
189
212
  )
190
213
 
191
214
  upgrade_parser = sub.add_parser(
@@ -219,16 +242,22 @@ def main(argv: Sequence[str] | None = None) -> int:
219
242
 
220
243
  handlers = {
221
244
  "start": session.cmd_open,
245
+ "up": session.cmd_open,
222
246
  "open": session.cmd_open,
223
247
  "stop": session.cmd_shut,
248
+ "down": session.cmd_shut,
224
249
  "shut": session.cmd_shut,
225
250
  "status": session.cmd_inspect,
251
+ "ps": session.cmd_inspect,
226
252
  "inspect": session.cmd_inspect,
227
253
  "connect": session.cmd_enter,
254
+ "ssh": session.cmd_enter,
228
255
  "enter": session.cmd_enter,
229
256
  "logs": session.cmd_trace,
257
+ "log": session.cmd_trace,
230
258
  "trace": session.cmd_trace,
231
259
  "restart": session.cmd_cycle,
260
+ "reload": session.cmd_cycle,
232
261
  "cycle": session.cmd_cycle,
233
262
  "upgrade": session.cmd_upgrade,
234
263
  "proxy": transports.cmd_proxy,
@@ -41,8 +41,17 @@ def _resolve_launch_settings(
41
41
  ) -> tuple[Path, int, int]:
42
42
  saved = saved or {}
43
43
  root_arg = getattr(args, "workspace", None) or saved.get("root") or "."
44
- port_arg = getattr(args, "port", None) or saved.get("port") or DEFAULT_PORT
45
- slot_arg = getattr(args, "slot", None) or saved.get("slot") or DEFAULT_SLOT
44
+ port_arg = getattr(args, "port", None)
45
+ if port_arg is None:
46
+ port_arg = getattr(args, "port_arg", None)
47
+ if port_arg is None:
48
+ port_arg = saved.get("port") or DEFAULT_PORT
49
+
50
+ slot_arg = getattr(args, "slot", None)
51
+ if slot_arg is None:
52
+ slot_arg = getattr(args, "slot_arg", None)
53
+ if slot_arg is None:
54
+ slot_arg = saved.get("slot") or DEFAULT_SLOT
46
55
 
47
56
  port_text = str(port_arg)
48
57
  if not port_text.isdigit() or not 1 <= int(port_text) <= 65535:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nullgate
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: Disposable SSH gateway into confined directory workspaces
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -14,6 +14,32 @@ Dynamic: license-file
14
14
 
15
15
  Disposable SSH gateway into confined directory workspaces for remote containers, ephemeral developer boxes, CI nodes, and cloud instances.
16
16
 
17
+ ## Quick start
18
+
19
+ Run Nullgate directly from PyPI without installing it first:
20
+
21
+ ```bash
22
+ # Share the current directory over the default Upterm provider
23
+ uvx nullgate start
24
+
25
+ # Share a specific workspace
26
+ uvx nullgate start /workspace
27
+
28
+ # Compact form: workspace, SSH port, srv.us slot, provider
29
+ uvx nullgate start /workspace 8022 1 -t srvus
30
+ ```
31
+
32
+ Then check the endpoint and print the SSH connection setup:
33
+
34
+ ```bash
35
+ uvx nullgate status
36
+ uvx nullgate connect
37
+ ```
38
+
39
+ Nullgate uses authorized SSH keys by default. Upterm needs a key in
40
+ `~/.ssh/authorized_keys`; use `--public-access` only for an intentionally public
41
+ temporary endpoint.
42
+
17
43
  ## Features
18
44
 
19
45
  - **Ingress Transports**: Publish endpoints via Upterm WebSocket relays (default), srv.us reverse tunnels, Cloudflare Worker relays, or Cloudflare Argo (`cloudflared`) tunnels.
@@ -55,6 +81,9 @@ nullgate start
55
81
  # Custom path, port, and slot
56
82
  nullgate start /workspace --ssh-port 4822 --tunnel-slot 1
57
83
 
84
+ # The same values in compact positional form
85
+ nullgate start /workspace 4822 1
86
+
58
87
  # Select specific transport provider
59
88
  nullgate start . --provider upterm
60
89
  nullgate start . --provider srvus
@@ -63,9 +92,11 @@ nullgate start . --provider cloudflared --public-hostname workspace.example.com
63
92
  ```
64
93
 
65
94
  Options:
66
- - `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `upterm`.
67
- - `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
68
- - `--public-hostname`: Public hostname used with `cloudflared`.
95
+ - `-p`, `--ssh-port`: Local SSH server port.
96
+ - `-s`, `--tunnel-slot`: srv.us tunnel slot.
97
+ - `-t`, `--provider`: Public connection provider (`upterm`, `srvus`, `cloudflare`, or `cloudflared`). Defaults to `upterm`.
98
+ - `-e`, `--relay-url`: WebSocket relay URL used with `upterm` or `cloudflare`.
99
+ - `-H`, `--public-hostname`: Public hostname used with `cloudflared`.
69
100
  - `--cloudflare-token`: Cloudflare tunnel credential, or set `NULLGATE_CLOUDFLARED_TOKEN`.
70
101
  - `--public-access`: Allow connections without credentials. This is unsafe on public endpoints.
71
102
  - `--no-public-access`: Require authentication.
@@ -126,9 +157,10 @@ nullgate upgrade
126
157
  nullgate upgrade --version 1.0.1
127
158
  ```
128
159
 
129
- The earlier command names `open`, `shut`, `inspect`, `enter`, `trace`, and
130
- `cycle` remain available as compatibility aliases. Their earlier option names
131
- also remain accepted, but new scripts should use the names documented above.
160
+ Short command aliases are `up`, `down`, `ps`, `ssh`, `log`, and `reload`.
161
+ The earlier names `open`, `shut`, `inspect`, `enter`, `trace`, and `cycle`
162
+ remain available as compatibility aliases. Their earlier option names also
163
+ remain accepted, but new scripts should use the names documented above.
132
164
 
133
165
  ## Authentication and Security Boundaries
134
166
 
@@ -126,6 +126,8 @@ class CLILifecycleTests(unittest.TestCase):
126
126
  self.assertEqual(session.DEFAULT_PORT, 4822)
127
127
  self.assertEqual(transports.DEFAULT_TRANSPORT, "upterm")
128
128
  self.assertIsNone(defaults.workspace)
129
+ self.assertIsNone(defaults.port_arg)
130
+ self.assertIsNone(defaults.slot_arg)
129
131
  self.assertIsNone(defaults.port)
130
132
  self.assertIsNone(defaults.slot)
131
133
  self.assertIsNone(defaults.accept)
@@ -158,6 +160,31 @@ class CLILifecycleTests(unittest.TestCase):
158
160
  self.assertEqual(clearer.transport, "upterm")
159
161
  self.assertEqual(clearer.endpoint, "wss://relay.example")
160
162
 
163
+ shorthand = parser.parse_args(
164
+ ["up", "/workspace", "2222", "2", "-t", "srvus"]
165
+ )
166
+ self.assertEqual(shorthand.command, "up")
167
+ self.assertEqual(shorthand.workspace, "/workspace")
168
+ self.assertEqual(shorthand.port_arg, 2222)
169
+ self.assertEqual(shorthand.slot_arg, 2)
170
+ self.assertEqual(shorthand.transport, "srvus")
171
+
172
+ short_options = parser.parse_args(
173
+ [
174
+ "start",
175
+ "-p", "2223",
176
+ "-s", "3",
177
+ "-t", "cloudflare",
178
+ "-e", "wss://relay.example",
179
+ "-H", "workspace.example.com",
180
+ ]
181
+ )
182
+ self.assertEqual(short_options.port, 2223)
183
+ self.assertEqual(short_options.slot, 3)
184
+ self.assertEqual(short_options.transport, "cloudflare")
185
+ self.assertEqual(short_options.endpoint, "wss://relay.example")
186
+ self.assertEqual(short_options.hostname, "workspace.example.com")
187
+
161
188
  legacy = parser.parse_args(
162
189
  ["open", "--no-accept", "--no-allow-tcp-forwarding", "--confine-sftp"]
163
190
  )
@@ -165,6 +192,28 @@ class CLILifecycleTests(unittest.TestCase):
165
192
  self.assertFalse(legacy.allow_tcp_forwarding)
166
193
  self.assertTrue(legacy.confine_sftp)
167
194
 
195
+ for alias, expected in (
196
+ ("down", "down"),
197
+ ("ps", "ps"),
198
+ ("ssh", "ssh"),
199
+ ("log", "log"),
200
+ ("reload", "reload"),
201
+ ):
202
+ self.assertEqual(parser.parse_args([alias]).command, expected)
203
+
204
+ def test_positional_start_values_and_options_resolve(self):
205
+ parser = commands.build_parser()
206
+ positional = parser.parse_args(["start", ".", "2222", "3"])
207
+ root, port, slot = session._resolve_launch_settings(positional)
208
+ self.assertEqual(root, Path.cwd())
209
+ self.assertEqual((port, slot), (2222, 3))
210
+
211
+ overridden = parser.parse_args(
212
+ ["start", ".", "2222", "3", "-p", "4444", "-s", "5"]
213
+ )
214
+ _, port, slot = session._resolve_launch_settings(overridden)
215
+ self.assertEqual((port, slot), (4444, 5))
216
+
168
217
  upgrade = parser.parse_args(["upgrade"])
169
218
  self.assertIsNone(upgrade.version)
170
219
  pinned = parser.parse_args(["upgrade", "--version", "1.2.3"])
@@ -1 +0,0 @@
1
- __version__ = "1.2.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes