impreza-cli 0.3.2__tar.gz → 0.5.0__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 (64) hide show
  1. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/PKG-INFO +297 -296
  2. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/README.md +255 -255
  3. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/__init__.py +25 -24
  4. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/__init__.py +7 -7
  5. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/_helpers.py +161 -128
  6. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/account.py +576 -576
  7. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/catalog.py +270 -270
  8. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/context.py +232 -232
  9. impreza_cli-0.5.0/impreza_cli/commands/dedicated.py +459 -0
  10. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/doctor.py +424 -427
  11. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/domain.py +858 -858
  12. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/invoice.py +271 -198
  13. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/key.py +104 -104
  14. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/orders.py +478 -478
  15. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/services.py +100 -100
  16. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/vps.py +812 -812
  17. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/vps_cloud.py +772 -772
  18. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/vps_proxmox.py +727 -727
  19. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/commands/webhooks.py +483 -483
  20. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/config.py +405 -405
  21. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/main.py +102 -100
  22. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/output.py +207 -207
  23. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/sdk.py +97 -97
  24. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli/state.py +94 -94
  25. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli.egg-info/PKG-INFO +297 -296
  26. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli.egg-info/SOURCES.txt +2 -0
  27. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli.egg-info/requires.txt +2 -1
  28. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/pyproject.toml +136 -114
  29. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/setup.cfg +4 -4
  30. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/conftest.py +24 -24
  31. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_account_commands.py +336 -336
  32. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_account_topup_commands.py +541 -541
  33. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_catalog_commands.py +343 -343
  34. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_config.py +252 -252
  35. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_context_commands.py +324 -324
  36. impreza_cli-0.5.0/tests/test_dedicated_commands.py +296 -0
  37. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_doctor_commands.py +409 -409
  38. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_domain_commands.py +848 -848
  39. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_invoice_commands.py +387 -242
  40. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_key_commands.py +168 -168
  41. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_orders_commands.py +406 -406
  42. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_2_2_smoke.py +138 -138
  43. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_2_3_smoke.py +117 -117
  44. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_2_4_smoke.py +208 -208
  45. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_2_5_smoke.py +140 -140
  46. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_2_6_smoke.py +146 -146
  47. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_3_1_smoke.py +225 -225
  48. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_3_2_smoke.py +222 -222
  49. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_3_3_smoke.py +179 -179
  50. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_3_4_smoke.py +223 -223
  51. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_3_5_smoke.py +183 -183
  52. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_3_6_smoke.py +112 -112
  53. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_phase_3_7_smoke.py +183 -183
  54. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_services_commands.py +145 -145
  55. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_vps_cloud_commands.py +506 -506
  56. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_vps_commands.py +949 -949
  57. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_vps_proxmox_commands.py +634 -634
  58. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_webhooks_commands.py +449 -449
  59. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/test_yaml_output.py +340 -340
  60. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli.egg-info/dependency_links.txt +0 -0
  61. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli.egg-info/entry_points.txt +0 -0
  62. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/impreza_cli.egg-info/top_level.txt +0 -0
  63. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/.gitkeep +0 -0
  64. {impreza_cli-0.3.2 → impreza_cli-0.5.0}/tests/__init__.py +0 -0
@@ -1,296 +1,297 @@
1
- Metadata-Version: 2.4
2
- Name: impreza-cli
3
- Version: 0.3.2
4
- Summary: Official command-line interface for the Impreza Host public REST API
5
- Author-email: Impreza Host <support@imprezahost.com>
6
- License: MIT
7
- Project-URL: Homepage, https://imprezahost.com
8
- Project-URL: Documentation, https://docs.imprezahost.com
9
- Project-URL: Repository, https://github.com/imprezahost/impreza-devkit
10
- Project-URL: Changelog, https://github.com/imprezahost/impreza-devkit/blob/master/CHANGELOG.md
11
- Keywords: impreza,hosting,cli,offshore,crypto
12
- Classifier: Development Status :: 4 - Beta
13
- Classifier: Environment :: Console
14
- Classifier: Intended Audience :: Developers
15
- Classifier: Intended Audience :: System Administrators
16
- Classifier: License :: OSI Approved :: MIT License
17
- Classifier: Operating System :: OS Independent
18
- Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3.10
20
- Classifier: Programming Language :: Python :: 3.11
21
- Classifier: Programming Language :: Python :: 3.12
22
- Classifier: Topic :: Internet :: WWW/HTTP
23
- Classifier: Topic :: Utilities
24
- Requires-Python: >=3.10
25
- Description-Content-Type: text/markdown
26
- Requires-Dist: impreza-sdk
27
- Requires-Dist: typer>=0.12
28
- Requires-Dist: rich>=13.7
29
- Requires-Dist: tomli>=2.0; python_version < "3.11"
30
- Requires-Dist: tomli-w>=1.0
31
- Provides-Extra: test
32
- Requires-Dist: pytest>=8.0; extra == "test"
33
- Requires-Dist: pytest-cov>=4.1; extra == "test"
34
- Requires-Dist: pyyaml>=6.0; extra == "test"
35
- Requires-Dist: types-PyYAML>=6.0; extra == "test"
36
- Provides-Extra: dev
37
- Requires-Dist: ruff>=0.5; extra == "dev"
38
- Requires-Dist: mypy>=1.8; extra == "dev"
39
- Provides-Extra: yaml
40
- Requires-Dist: pyyaml>=6.0; extra == "yaml"
41
-
42
- # `impreza-cli` — Official CLI for Impreza Host
43
-
44
- Command-line interface for the Impreza Host public REST API.
45
- Built on top of [`impreza-sdk`](../sdk-python/README.md) — same
46
- auth model, same Tor support, same retry behaviour, plus
47
- multi-context configuration and Rich-rendered tables for human-
48
- friendly output.
49
-
50
- ```bash
51
- pip install impreza-cli
52
- ```
53
-
54
- Requires Python 3.10+. See [`../CHANGELOG.md`](../CHANGELOG.md) for
55
- release history.
56
-
57
- ## Quickstart
58
-
59
- ```bash
60
- # 1. Add a context with your API credentials. Generate keys in
61
- # Impreza Account → API Keys; whitelist the calling
62
- # machine's IP at the same screen.
63
- $ impreza context create personal --key imp_... --secret ...
64
- Context 'personal' created and set as default.
65
-
66
- # 2. Confirm everything works. impreza doctor runs five sequenced
67
- # health checks (config, API reachable, key status, IP
68
- # whitelist, account profile) and exits 0 only if all pass.
69
- $ impreza doctor
70
-
71
- impreza doctor
72
- ----------------------------------------
73
- [OK] active-context: Default context
74
- [OK] api-reachable: GET /account/api-keys/self OK (142ms)
75
- key prefix='imp_a1b2c3d4', label='devkit'
76
- [OK] key-status: status='active'
77
- [OK] ip-whitelist: request_ip 200.1.2.3 matches entry ('home')
78
- [OK] account-profile: Jane Doe <jane@example.com>, balance 5.00 USD
79
- registered 2024-01-15
80
- ----------------------------------------
81
- All checks passed. 5/5.
82
-
83
- # 3. Read commands span every resource group:
84
- $ impreza account info # profile + balance
85
- $ impreza vps list # across both backends
86
- $ impreza domain check example.com mydomain.io
87
- $ impreza catalog products --group "VPS"
88
-
89
- # 4. Pipe into jq for scripting (every read verb supports --output
90
- # json | yaml):
91
- $ impreza invoice list --output json \
92
- | jq '[.[] | select(.status == "Unpaid")] | length'
93
-
94
- # 5. Write verbs are gated by confirm_or_exit so you don't lose
95
- # data accidentally; pass --yes / -y to skip prompts in scripts:
96
- $ impreza vps reboot 17988
97
- $ impreza vps proxmox snapshots create 17988 pre-update
98
- $ impreza domain dns add example.com --type A --name www --value 1.2.3.4
99
-
100
- # 6. Crypto top-up. --browser opens the BTCPay invoice URL
101
- # automatically; --wait polls until the gateway confirms
102
- # (default 2h timeout matches server-side invoice expiry).
103
- $ impreza account topup --amount 50 --method xmr --browser --wait
104
- ```
105
-
106
- ## Authentication
107
-
108
- Two ways to authenticate. The CLI tries them in order:
109
-
110
- 1. **Context** (recommended) — `impreza context create <name>` stores
111
- credentials in a config file; commands read them automatically.
112
- Per-invocation override via `impreza --context other <command>`.
113
-
114
- 2. **Environment variables** — `IMPREZA_API_KEY` + `IMPREZA_API_SECRET`.
115
- Useful in CI, but contexts are preferred for local work.
116
-
117
- The config file lives at:
118
-
119
- | OS | Path |
120
- |---|---|
121
- | Linux | `$XDG_CONFIG_HOME/impreza/config.toml` (default `~/.config/impreza/config.toml`) |
122
- | macOS | `~/Library/Application Support/impreza/config.toml` |
123
- | Windows | `%APPDATA%\impreza\config.toml` |
124
-
125
- Override with `IMPREZA_CONFIG=/path/to/config.toml` for testing or
126
- non-standard layouts.
127
-
128
- On POSIX, the config file is `chmod 0o600` after every write so only
129
- the owner can read the credentials. Windows ACLs are left to the OS
130
- default.
131
-
132
- ## Commands
133
-
134
- The CLI groups commands by resource. Run `impreza <group> --help`
135
- to see the full subcommand list, or `impreza <group> <command>
136
- --help` for option-level detail.
137
-
138
- | Group | Verbs | Notes |
139
- |---|---|---|
140
- | `context` | `create / use / list / current / delete` | Local credential management — never hits the network |
141
- | `doctor` | (single command) | Health check — config + API reachable + key status + IP whitelist + account profile |
142
- | `account` | `info / balance / services / topup / topup-status` | Profile + balance + services + crypto top-up |
143
- | `catalog` | `products / product / product-groups / tlds` | Pre-purchase discovery |
144
- | `domain` | `show / check / pricing / register / transfer / set-nameservers / lock / unlock / id-protection / raa-verify / gdpr-auth / transfer-approval` + `domain dns list / add / update / delete / activate` | Domain registrations + full DNS CRUD |
145
- | `vps` | `list / show / status / start / stop / reboot / shutdown / set-hostname / set-password / reinstall / migrate / cancel` + `vps proxmox snapshots / backups / backup-schedules / network` + `vps cloud images / rescue / iso / ssh-keys / vnc / vnc-password / resize / boot-order / ipv6` | Cross-backend (Proxmox + Cloud) VPS with smart dispatch |
146
- | `order` | `list / show / create / upgrade` | Submit / browse product orders |
147
- | `service` | `cancel` | Submit cancellation request (any service) |
148
- | `webhook` | `list / show / create / update / delete / rotate-secret / deliveries / event-types` | Webhook subscription management + delivery history. Event-payload contract documented in [`../openapi/asyncapi.yaml`](../openapi/asyncapi.yaml). |
149
- | `invoice` | `list / show` | Invoices with line items + transactions |
150
- | `key` | `whoami` | Active API key identity + IP whitelist |
151
-
152
- **Conventions:**
153
-
154
- - Destructive verbs prompt for confirmation; pass `--yes` / `-y`
155
- to skip the prompt in scripts.
156
- - Operation-returning verbs (`vps reinstall`, `vps migrate`,
157
- `vps proxmox snapshots rollback`, `vps proxmox backups
158
- create/restore`) accept `--wait` to block on the Proxmox queue,
159
- with `--timeout` (default 600 s for fast ops, 1800 s for the
160
- slower restores).
161
- - Cost-incurring verbs (`domain register/transfer/id-protection`,
162
- `order create/upgrade`, `account topup`) call out the
163
- balance impact in the confirmation prompt; an
164
- `InsufficientCredit` 402 surfaces with a hint pointing at
165
- `impreza account topup`.
166
- - Verbs that mutate a resource emit a green success line on
167
- stdout; queued / reboot-required state changes emit a cyan
168
- info line. Errors are red on stderr.
169
-
170
- **Service termination policy:** `service cancel` / `vps cancel`
171
- submit an `AddCancelRequest` — staff approves the actual
172
- termination. There is no direct customer path to terminate a
173
- service or remove a service suspension (suspension is
174
- billing-state and is removed automatically when the overdue
175
- invoice is paid, or manually by staff after an abuse hold is
176
- resolved).
177
-
178
- ## Output formats
179
-
180
- Every command supports `--output table|json|yaml` (short form `-o`).
181
-
182
- | Format | Default | Best for |
183
- |---|---|---|
184
- | `table` | yes | human reading at the terminal |
185
- | `json` | | piping into `jq`, automation, scripting |
186
- | `yaml` | | human-editable config snapshots, CI/CD pipelines |
187
-
188
- YAML output requires the optional `pyyaml` dependency:
189
-
190
- ```bash
191
- pip install impreza-cli[yaml]
192
- ```
193
-
194
- The CLI raises a clear `RuntimeError` pointing at the install hint
195
- if you select `--output yaml` without it.
196
-
197
- The flag works at both the global level and per-command:
198
-
199
- ```bash
200
- # Global default for the invocation
201
- impreza --output json account info
202
-
203
- # Per-command override (wins over global)
204
- impreza --output yaml account info --output table
205
- ```
206
-
207
- ## Tab completion
208
-
209
- Typer ships completion for `bash`, `zsh`, `fish`, and PowerShell
210
- out of the box:
211
-
212
- ```bash
213
- # Install for the current shell (auto-detected)
214
- impreza --install-completion
215
-
216
- # Or explicitly
217
- impreza --install-completion bash # / zsh / fish / powershell
218
-
219
- # Inspect the script before installing
220
- impreza --show-completion bash
221
- ```
222
-
223
- After installing, restart the shell (or `source ~/.bashrc` /
224
- equivalent) and `impreza <TAB>` should suggest resource groups,
225
- `impreza account <TAB>` should suggest verbs, and so on.
226
-
227
- ## Tor
228
-
229
- Inherited from the SDK. Three knobs:
230
-
231
- ```bash
232
- # Per-context override at create time
233
- impreza context create offshore \
234
- --key imp_... --secret ... \
235
- # No --proxy flag yet; for now, set IMPREZA_USE_TOR before invoking
236
-
237
- # Env var, picked up by the SDK transparently
238
- IMPREZA_USE_TOR=1 impreza account info
239
-
240
- # Programmatic via the SDK (Python users skip the CLI for this)
241
- ```
242
-
243
- The SDK's `auto_tor=True` path (probe Tor, fall back to clearnet)
244
- isn't surfaced through the CLI yet — coming in a future release
245
- alongside the `--via-tor` shortcut.
246
-
247
- ## Error handling
248
-
249
- The CLI maps SDK exceptions to friendly stderr messages and a
250
- non-zero exit code, matching the format `ImprezaError.__str__`
251
- produces:
252
-
253
- ```
254
- Error: Invalid API credentials. (code=UNAUTHORIZED) [request_id=req_abc]
255
- ```
256
-
257
- Tracebacks never leak from expected failures (auth errors, missing
258
- contexts, 404s, 429s, etc.). Bugs in the CLI itself still raise so
259
- the traceback isn't swallowed — that's intentional.
260
-
261
- ## Development
262
-
263
- ```bash
264
- git clone https://github.com/imprezahost/impreza-devkit.git
265
- cd impreza-devkit/cli-python
266
-
267
- python -m venv .venv
268
- # Linux/macOS: source .venv/bin/activate
269
- # Windows PowerShell: .venv\Scripts\Activate.ps1
270
-
271
- # Install editable + test/dev/yaml extras + the SDK as a path dep
272
- pip install -e ../sdk-python -e ".[test,dev,yaml]"
273
-
274
- pytest # unit + Typer-runner E2E
275
- ruff check
276
- mypy --strict impreza_cli
277
- ```
278
-
279
- To run the live integration smokes (skipped silently without creds):
280
-
281
- ```bash
282
- export IMPREZA_API_KEY="imp_..."
283
- export IMPREZA_API_SECRET="..."
284
- # Optional, for `impreza domain show / dns list`:
285
- export IMPREZA_TEST_DOMAIN="<a domain on your account>"
286
-
287
- pytest -v -s tests/
288
- ```
289
-
290
- The smokes exercise the same surface as the unit tests against the
291
- real API, so they catch contract drift between the CLI and the
292
- server.
293
-
294
- ## License
295
-
296
- MIT. See [`../LICENSE`](../LICENSE) at the repository root.
1
+ Metadata-Version: 2.4
2
+ Name: impreza-cli
3
+ Version: 0.5.0
4
+ Summary: Official command-line interface for the Impreza Host public REST API
5
+ Author-email: Impreza Host <support@imprezahost.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://imprezahost.com
8
+ Project-URL: Documentation, https://docs.imprezahost.com
9
+ Project-URL: Repository, https://github.com/imprezahost/impreza-devkit
10
+ Project-URL: Changelog, https://github.com/imprezahost/impreza-devkit/blob/master/CHANGELOG.md
11
+ Keywords: impreza,hosting,cli,offshore,crypto
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: System Administrators
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ Requires-Dist: impreza-sdk<0.6,>=0.5.0
27
+ Requires-Dist: typer>=0.12
28
+ Requires-Dist: rich>=13.7
29
+ Requires-Dist: click>=8.0
30
+ Requires-Dist: tomli>=2.0; python_version < "3.11"
31
+ Requires-Dist: tomli-w>=1.0
32
+ Provides-Extra: test
33
+ Requires-Dist: pytest>=8.0; extra == "test"
34
+ Requires-Dist: pytest-cov>=4.1; extra == "test"
35
+ Requires-Dist: pyyaml>=6.0; extra == "test"
36
+ Requires-Dist: types-PyYAML>=6.0; extra == "test"
37
+ Provides-Extra: dev
38
+ Requires-Dist: ruff>=0.5; extra == "dev"
39
+ Requires-Dist: mypy>=1.8; extra == "dev"
40
+ Provides-Extra: yaml
41
+ Requires-Dist: pyyaml>=6.0; extra == "yaml"
42
+
43
+ # `impreza-cli` — Official CLI for Impreza Host
44
+
45
+ Command-line interface for the Impreza Host public REST API.
46
+ Built on top of [`impreza-sdk`](../sdk-python/README.md) — same
47
+ auth model, same Tor support, same retry behaviour, plus
48
+ multi-context configuration and Rich-rendered tables for human-
49
+ friendly output.
50
+
51
+ ```bash
52
+ pip install impreza-cli
53
+ ```
54
+
55
+ Requires Python 3.10+. See [`../CHANGELOG.md`](../CHANGELOG.md) for
56
+ release history.
57
+
58
+ ## Quickstart
59
+
60
+ ```bash
61
+ # 1. Add a context with your API credentials. Generate keys in
62
+ # Impreza Account → API Keys; whitelist the calling
63
+ # machine's IP at the same screen.
64
+ $ impreza context create personal --key imp_... --secret ...
65
+ Context 'personal' created and set as default.
66
+
67
+ # 2. Confirm everything works. impreza doctor runs five sequenced
68
+ # health checks (config, API reachable, key status, IP
69
+ # whitelist, account profile) and exits 0 only if all pass.
70
+ $ impreza doctor
71
+
72
+ impreza doctor
73
+ ----------------------------------------
74
+ [OK] active-context: Default context
75
+ [OK] api-reachable: GET /account/api-keys/self OK (142ms)
76
+ key prefix='imp_a1b2c3d4', label='devkit'
77
+ [OK] key-status: status='active'
78
+ [OK] ip-whitelist: request_ip 198.51.100.23 matches entry ('home')
79
+ [OK] account-profile: Jane Doe <jane@example.com>, balance 5.00 USD
80
+ registered 2024-01-15
81
+ ----------------------------------------
82
+ All checks passed. 5/5.
83
+
84
+ # 3. Read commands span every resource group:
85
+ $ impreza account info # profile + balance
86
+ $ impreza vps list # across both backends
87
+ $ impreza domain check example.com mydomain.io
88
+ $ impreza catalog products --group "VPS"
89
+
90
+ # 4. Pipe into jq for scripting (every read verb supports --output
91
+ # json | yaml):
92
+ $ impreza invoice list --output json \
93
+ | jq '[.[] | select(.status == "Unpaid")] | length'
94
+
95
+ # 5. Write verbs are gated by confirm_or_exit so you don't lose
96
+ # data accidentally; pass --yes / -y to skip prompts in scripts:
97
+ $ impreza vps reboot 17988
98
+ $ impreza vps proxmox snapshots create 17988 pre-update
99
+ $ impreza domain dns add example.com --type A --name www --value 203.0.113.24
100
+
101
+ # 6. Crypto top-up. --browser opens the BTCPay invoice URL
102
+ # automatically; --wait polls until the gateway confirms
103
+ # (default 2h timeout matches server-side invoice expiry).
104
+ $ impreza account topup --amount 50 --method xmr --browser --wait
105
+ ```
106
+
107
+ ## Authentication
108
+
109
+ Two ways to authenticate. The CLI tries them in order:
110
+
111
+ 1. **Context** (recommended) — `impreza context create <name>` stores
112
+ credentials in a config file; commands read them automatically.
113
+ Per-invocation override via `impreza --context other <command>`.
114
+
115
+ 2. **Environment variables** — `IMPREZA_API_KEY` + `IMPREZA_API_SECRET`.
116
+ Useful in CI, but contexts are preferred for local work.
117
+
118
+ The config file lives at:
119
+
120
+ | OS | Path |
121
+ |---|---|
122
+ | Linux | `$XDG_CONFIG_HOME/impreza/config.toml` (default `~/.config/impreza/config.toml`) |
123
+ | macOS | `~/Library/Application Support/impreza/config.toml` |
124
+ | Windows | `%APPDATA%\impreza\config.toml` |
125
+
126
+ Override with `IMPREZA_CONFIG=/path/to/config.toml` for testing or
127
+ non-standard layouts.
128
+
129
+ On POSIX, the config file is `chmod 0o600` after every write so only
130
+ the owner can read the credentials. Windows ACLs are left to the OS
131
+ default.
132
+
133
+ ## Commands
134
+
135
+ The CLI groups commands by resource. Run `impreza <group> --help`
136
+ to see the full subcommand list, or `impreza <group> <command>
137
+ --help` for option-level detail.
138
+
139
+ | Group | Verbs | Notes |
140
+ |---|---|---|
141
+ | `context` | `create / use / list / current / delete` | Local credential management — never hits the network |
142
+ | `doctor` | (single command) | Health check — config + API reachable + key status + IP whitelist + account profile |
143
+ | `account` | `info / balance / services / topup / topup-status` | Profile + balance + services + crypto top-up |
144
+ | `catalog` | `products / product / product-groups / tlds` | Pre-purchase discovery |
145
+ | `domain` | `show / check / pricing / register / transfer / set-nameservers / lock / unlock / id-protection / raa-verify / gdpr-auth / transfer-approval` + `domain dns list / add / update / delete / activate` | Domain registrations + full DNS CRUD |
146
+ | `vps` | `list / show / status / start / stop / reboot / shutdown / set-hostname / set-password / reinstall / migrate / cancel` + `vps proxmox snapshots / backups / backup-schedules / network` + `vps cloud images / rescue / iso / ssh-keys / vnc / vnc-password / resize / boot-order / ipv6` | Cross-backend (Proxmox + Cloud) VPS with smart dispatch |
147
+ | `order` | `list / show / create / upgrade` | Submit / browse product orders |
148
+ | `service` | `cancel` | Submit cancellation request (any service) |
149
+ | `webhook` | `list / show / create / update / delete / rotate-secret / deliveries / event-types` | Webhook subscription management + delivery history. Event-payload contract documented in [`../openapi/asyncapi.yaml`](../openapi/asyncapi.yaml). |
150
+ | `invoice` | `list / show` | Invoices with line items + transactions |
151
+ | `key` | `whoami` | Active API key identity + IP whitelist |
152
+
153
+ **Conventions:**
154
+
155
+ - Destructive verbs prompt for confirmation; pass `--yes` / `-y`
156
+ to skip the prompt in scripts.
157
+ - Operation-returning verbs (`vps reinstall`, `vps migrate`,
158
+ `vps proxmox snapshots rollback`, `vps proxmox backups
159
+ create/restore`) accept `--wait` to block on the Proxmox queue,
160
+ with `--timeout` (default 600 s for fast ops, 1800 s for the
161
+ slower restores).
162
+ - Cost-incurring verbs (`domain register/transfer/id-protection`,
163
+ `order create/upgrade`, `account topup`) call out the
164
+ balance impact in the confirmation prompt; an
165
+ `InsufficientCredit` 402 surfaces with a hint pointing at
166
+ `impreza account topup`.
167
+ - Verbs that mutate a resource emit a green success line on
168
+ stdout; queued / reboot-required state changes emit a cyan
169
+ info line. Errors are red on stderr.
170
+
171
+ **Service termination policy:** `service cancel` / `vps cancel`
172
+ submit an `AddCancelRequest` — staff approves the actual
173
+ termination. There is no direct customer path to terminate a
174
+ service or remove a service suspension (suspension is
175
+ billing-state and is removed automatically when the overdue
176
+ invoice is paid, or manually by staff after an abuse hold is
177
+ resolved).
178
+
179
+ ## Output formats
180
+
181
+ Every command supports `--output table|json|yaml` (short form `-o`).
182
+
183
+ | Format | Default | Best for |
184
+ |---|---|---|
185
+ | `table` | yes | human reading at the terminal |
186
+ | `json` | | piping into `jq`, automation, scripting |
187
+ | `yaml` | | human-editable config snapshots, CI/CD pipelines |
188
+
189
+ YAML output requires the optional `pyyaml` dependency:
190
+
191
+ ```bash
192
+ pip install impreza-cli[yaml]
193
+ ```
194
+
195
+ The CLI raises a clear `RuntimeError` pointing at the install hint
196
+ if you select `--output yaml` without it.
197
+
198
+ The flag works at both the global level and per-command:
199
+
200
+ ```bash
201
+ # Global default for the invocation
202
+ impreza --output json account info
203
+
204
+ # Per-command override (wins over global)
205
+ impreza --output yaml account info --output table
206
+ ```
207
+
208
+ ## Tab completion
209
+
210
+ Typer ships completion for `bash`, `zsh`, `fish`, and PowerShell
211
+ out of the box:
212
+
213
+ ```bash
214
+ # Install for the current shell (auto-detected)
215
+ impreza --install-completion
216
+
217
+ # Or explicitly
218
+ impreza --install-completion bash # / zsh / fish / powershell
219
+
220
+ # Inspect the script before installing
221
+ impreza --show-completion bash
222
+ ```
223
+
224
+ After installing, restart the shell (or `source ~/.bashrc` /
225
+ equivalent) and `impreza <TAB>` should suggest resource groups,
226
+ `impreza account <TAB>` should suggest verbs, and so on.
227
+
228
+ ## Tor
229
+
230
+ Inherited from the SDK. Three knobs:
231
+
232
+ ```bash
233
+ # Per-context override at create time
234
+ impreza context create offshore \
235
+ --key imp_... --secret ... \
236
+ # No --proxy flag yet; for now, set IMPREZA_USE_TOR before invoking
237
+
238
+ # Env var, picked up by the SDK transparently
239
+ IMPREZA_USE_TOR=1 impreza account info
240
+
241
+ # Programmatic via the SDK (Python users skip the CLI for this)
242
+ ```
243
+
244
+ The SDK's `auto_tor=True` path (probe Tor, fall back to clearnet)
245
+ isn't surfaced through the CLI yet — coming in a future release
246
+ alongside the `--via-tor` shortcut.
247
+
248
+ ## Error handling
249
+
250
+ The CLI maps SDK exceptions to friendly stderr messages and a
251
+ non-zero exit code, matching the format `ImprezaError.__str__`
252
+ produces:
253
+
254
+ ```
255
+ Error: Invalid API credentials. (code=UNAUTHORIZED) [request_id=req_abc]
256
+ ```
257
+
258
+ Tracebacks never leak from expected failures (auth errors, missing
259
+ contexts, 404s, 429s, etc.). Bugs in the CLI itself still raise so
260
+ the traceback isn't swallowed — that's intentional.
261
+
262
+ ## Development
263
+
264
+ ```bash
265
+ git clone https://github.com/imprezahost/impreza-devkit.git
266
+ cd impreza-devkit/cli-python
267
+
268
+ python -m venv .venv
269
+ # Linux/macOS: source .venv/bin/activate
270
+ # Windows PowerShell: .venv\Scripts\Activate.ps1
271
+
272
+ # Install editable + test/dev/yaml extras + the SDK as a path dep
273
+ pip install -e ../sdk-python -e ".[test,dev,yaml]"
274
+
275
+ pytest # unit + Typer-runner E2E
276
+ ruff check
277
+ mypy --strict impreza_cli
278
+ ```
279
+
280
+ To run the live integration smokes (skipped silently without creds):
281
+
282
+ ```bash
283
+ export IMPREZA_API_KEY="imp_..."
284
+ export IMPREZA_API_SECRET="..."
285
+ # Optional, for `impreza domain show / dns list`:
286
+ export IMPREZA_TEST_DOMAIN="<a domain on your account>"
287
+
288
+ pytest -v -s tests/
289
+ ```
290
+
291
+ The smokes exercise the same surface as the unit tests against the
292
+ real API, so they catch contract drift between the CLI and the
293
+ server.
294
+
295
+ ## License
296
+
297
+ MIT. See [`../LICENSE`](../LICENSE) at the repository root.