amd-oneclick-sdk 1.0.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 (36) hide show
  1. amd_oneclick_sdk-1.0.0/PKG-INFO +651 -0
  2. amd_oneclick_sdk-1.0.0/README.md +635 -0
  3. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/__init__.py +45 -0
  4. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/__init__.py +7 -0
  5. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/auth_commands.py +225 -0
  6. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/catalog.py +541 -0
  7. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/common.py +51 -0
  8. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/completion.py +120 -0
  9. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/credits.py +22 -0
  10. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/dashboard.py +101 -0
  11. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/device_auth.py +103 -0
  12. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/instance_commands.py +378 -0
  13. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/instance_create.py +85 -0
  14. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/lifecycle.py +326 -0
  15. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/main.py +247 -0
  16. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/output.py +435 -0
  17. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/parser.py +363 -0
  18. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/profiles.py +152 -0
  19. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/_cli/registry.py +147 -0
  20. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/auth.py +204 -0
  21. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/cli.py +32 -0
  22. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/client.py +499 -0
  23. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/defaults.py +15 -0
  24. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/errors.py +96 -0
  25. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/keys.py +138 -0
  26. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/prompt.py +86 -0
  27. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/rcc_config.py +607 -0
  28. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk/security.py +149 -0
  29. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk.egg-info/PKG-INFO +651 -0
  30. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk.egg-info/SOURCES.txt +34 -0
  31. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk.egg-info/dependency_links.txt +1 -0
  32. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk.egg-info/entry_points.txt +3 -0
  33. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk.egg-info/requires.txt +3 -0
  34. amd_oneclick_sdk-1.0.0/amd_oneclick_sdk.egg-info/top_level.txt +1 -0
  35. amd_oneclick_sdk-1.0.0/pyproject.toml +32 -0
  36. amd_oneclick_sdk-1.0.0/setup.cfg +4 -0
@@ -0,0 +1,651 @@
1
+ Metadata-Version: 2.4
2
+ Name: amd-oneclick-sdk
3
+ Version: 1.0.0
4
+ Summary: Scoped command-line SDK for Radeon Cloud accounts and instances
5
+ License-Expression: MIT
6
+ Keywords: amd,gpu,rocm,jupyter,radeon-cloud
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Environment :: Console
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Topic :: System :: Distributed Computing
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest>=7.0; extra == "dev"
16
+
17
+ # Radeon Cloud CLI (RCC)
18
+
19
+ RCC is the command-line interface and Python SDK for connecting a local
20
+ workstation to an existing Radeon Cloud account and managing that account's
21
+ Jupyter instance. Browser authorization uses the existing GitHub, email, or SSO
22
+ login flow and returns a scoped, expiring `rcc_...` resource token to the CLI.
23
+
24
+ > **Integration status:** this package is version `1.0.0` and implements the
25
+ > first Radeon-Cloud-Internal integration. The server feature is disabled by
26
+ > default with `RCC_CLI_ENABLED=false`; operators must apply the RCC database
27
+ > migration and verify the public routes before enabling it. Use
28
+ > `rcc capabilities` to inspect the contract exposed by a deployment.
29
+
30
+ For the Chinese integration handoff, including interface ownership, token
31
+ scopes, implemented safeguards, current limitations, and the joint test
32
+ checklist, see [主项目接口对接与联调清单](../docs/ops/rcc-sdk-main-project-handoff-cn.md).
33
+
34
+ The built-in Manager endpoint is `https://radeon-global.anruicloud.com`.
35
+ Operators can select another deployment with a named profile, `--base-url`, or
36
+ the matched `RCC_URL` / `RCC_TOKEN` environment variables described below.
37
+
38
+ An RCC token is deliberately separate from the existing `rc-...` model
39
+ forwarding / Token Factory credential:
40
+
41
+ - `rcc_...` authorizes scoped account, Catalog, and Jupyter-instance actions.
42
+ - `rc-...` remains a model-forwarding credential and is rejected by this SDK
43
+ before a resource request is sent.
44
+
45
+ ## Current capabilities
46
+
47
+ - **Browser-assisted account authorization:** approve one workstation through
48
+ the existing Radeon Cloud website without copying a web session or password
49
+ into the CLI.
50
+ - **Per-device credentials:** every login receives its own named, scoped,
51
+ expiring token; logout revokes only the selected token.
52
+ - **Multiple local accounts:** save named account profiles and select an
53
+ explicit identity for each command.
54
+ - **Read-only account and Credits status:** inspect the signed-in identity and
55
+ GPU-hour balance without exposing the legacy Token Factory credential.
56
+ - **Administrator Catalog discovery:** list and search approved environments,
57
+ resource pools, and resource templates.
58
+ - **Jupyter lifecycle:** create, inspect, watch, read logs from, open, and delete
59
+ the current account-owned instance.
60
+ - **Safe browser handoff:** open a ready Jupyter instance through a short-lived,
61
+ single-use URL.
62
+ - **Managed SSH:** reuse a matching local identity, append its public key only
63
+ when needed, and enter a ready instance with `rcc instance ssh`.
64
+ - **Automation output:** use versioned `human`, `json`, or `ndjson` output and
65
+ generate shell completion locally.
66
+
67
+ The Radeon Cloud service never receives a kubeconfig, Kubernetes
68
+ ServiceAccount token, SSH private key, internal Launch Job identifier,
69
+ workload API key, or OpenCode password.
70
+
71
+ ## Installation
72
+
73
+ ### Requirements
74
+
75
+ - Python 3.9 or newer.
76
+ - Linux, macOS, or Windows 10/11.
77
+ - A browser that can reach the configured Radeon Cloud login page. A browser is
78
+ not required on the CLI host when `--no-browser` is used.
79
+ - OpenSSH (`ssh` and `ssh-keygen`) when managed SSH is used.
80
+
81
+ The package has no third-party Python runtime dependencies.
82
+
83
+ ### Install from the repository
84
+
85
+ From the Radeon-Cloud-Internal repository root:
86
+
87
+ ```bash
88
+ python3 -m pip install ./sdk
89
+ rcc --version
90
+ ```
91
+
92
+ For SDK development:
93
+
94
+ ```bash
95
+ python3 -m pip install -e ./sdk
96
+ ```
97
+
98
+ ### Install a release wheel
99
+
100
+ ```bash
101
+ pipx install ./amd_oneclick_sdk-1.0.0-py3-none-any.whl
102
+ rcc --version
103
+ ```
104
+
105
+ ### Packaged Linux and Windows bundles
106
+
107
+ A release bundle places exactly one RCC wheel beside its platform installer.
108
+ After extracting the bundle, run:
109
+
110
+ ```bash
111
+ # Linux, from the extracted linux bundle
112
+ bash install-rcc.sh
113
+ ```
114
+
115
+ ```text
116
+ Windows: double-click install-rcc.cmd or run it from Command Prompt.
117
+ ```
118
+
119
+ Both installers create an isolated per-user Python environment and finish by
120
+ printing the installed RCC version. Administrator privileges are not required.
121
+
122
+ Both `rcc` and the compatibility executable `amd-oneclick` invoke the same CLI.
123
+
124
+ ## Quick start
125
+
126
+ ### 1. Sign in
127
+
128
+ ```bash
129
+ rcc auth login --account work
130
+ rcc auth status
131
+ rcc doctor
132
+ ```
133
+
134
+ RCC opens a one-time verification page on the configured Radeon Cloud site.
135
+ Sign in through the normal web flow, review the device name, and approve the
136
+ request. On a headless or remote workstation, print the link instead:
137
+
138
+ ```bash
139
+ rcc auth login --account work --no-browser
140
+ ```
141
+
142
+ Open that link in a trusted browser before the transaction expires. The CLI
143
+ polls only the one-time authorization transaction; it never reads browser
144
+ cookies.
145
+
146
+ ### 2. Inspect approved resources
147
+
148
+ ```bash
149
+ rcc credits status
150
+ rcc catalog list
151
+ rcc catalog list --kind environment
152
+ rcc catalog list --kind resource_pool
153
+ rcc catalog list --kind resource_template
154
+ rcc capabilities
155
+ ```
156
+
157
+ Catalog `available` means the account is policy-eligible at read time. It does
158
+ not reserve a GPU or guarantee that capacity is currently schedulable.
159
+
160
+ ### 3. Create a Jupyter instance
161
+
162
+ Configure the account's SSH key once before its first SSH-enabled launch:
163
+
164
+ ```bash
165
+ rcc instance add-key
166
+ ```
167
+
168
+ This validates an existing local identity or offers to generate Ed25519, then
169
+ appends only its public half. Instance creation enables SSH by default; use
170
+ `--no-ssh` only when SSH is not wanted.
171
+ Direct `--token` or `RCC_TOKEN` credentials must also pass `--identity-file`;
172
+ RCC never borrows the active named account's private key for another token.
173
+
174
+ Run the command in an interactive terminal to select Catalog values, or pass
175
+ all selectors explicitly for automation:
176
+
177
+ ```bash
178
+ rcc instance create \
179
+ --env REVIEWED_ENVIRONMENT \
180
+ --pod-type RESOURCE_POOL \
181
+ --resource-template RESOURCE_TEMPLATE
182
+ ```
183
+
184
+ By default, the command waits for readiness by polling the current-instance
185
+ endpoint directly. It does not read or expose an internal Launch Job. To return
186
+ as soon as creation is accepted:
187
+
188
+ ```bash
189
+ rcc instance create \
190
+ --env REVIEWED_ENVIRONMENT \
191
+ --pod-type RESOURCE_POOL \
192
+ --resource-template RESOURCE_TEMPLATE \
193
+ --no-wait
194
+
195
+ rcc instance status --watch
196
+ rcc instance logs
197
+ ```
198
+
199
+ Use `--idempotency-key KEY` when retrying the same logical create operation
200
+ after a lost response. The same key must not be reused for a different launch.
201
+
202
+ ### 4. Open the instance
203
+
204
+ ```bash
205
+ rcc instance open
206
+ ```
207
+
208
+ For a headless machine, print the short-lived URL and open it on another trusted
209
+ device:
210
+
211
+ ```bash
212
+ rcc instance open --print
213
+ ```
214
+
215
+ The URL is single-use and sensitive even though it contains neither the RCC
216
+ token nor an internal workload credential. Do not place it in logs or chat.
217
+
218
+ ### 5. Release the GPU
219
+
220
+ ```bash
221
+ rcc instance delete --yes
222
+ rcc instance status
223
+ ```
224
+
225
+ Deletion is explicit. Logging out or removing a local profile does not stop an
226
+ instance or GPU billing. A successful response that says the instance is
227
+ shutting down does not mean cleanup has completed; continue checking status
228
+ until no active instance is reported.
229
+
230
+ ## Supported command surface
231
+
232
+ ```text
233
+ rcc status
234
+ rcc auth login|status|logout
235
+ rcc account add|list|current|use|remove
236
+ rcc credits status
237
+ rcc catalog list|show|search
238
+ rcc doctor
239
+ rcc capabilities
240
+ rcc instance create|add-key|list|status|logs|open|ssh|delete
241
+ rcc completion bash|zsh|fish|powershell
242
+ ```
243
+
244
+ The following table is the first-release command-to-API contract. Commands
245
+ marked **local** require no server endpoint.
246
+
247
+ | Command | RCC BFF request(s) | Required scope / behavior |
248
+ |---|---|---|
249
+ | `rcc auth login` | `POST /api/cli/auth/start`, browser `GET/POST /auth/cli/verify/{code}`, then `POST /api/cli/auth/poll` | Login start and poll are one-time, unauthenticated transactions; browser approval requires the existing web session. |
250
+ | `rcc auth status` | `GET /api/cli/auth/status` | `account:read`; `--all` checks `GET /api/cli/account` for each saved profile. |
251
+ | `rcc auth logout` | `POST /api/cli/auth/logout` | `account:read`; revokes the effective device token; removes a profile only when it supplied that token. |
252
+ | `rcc account add` | Same device-authorization flow as `auth login` | Saves a new named local profile after browser approval. |
253
+ | `rcc account list/current/use` | **Local** | Reads or updates `~/.radeon-cloud/config.json`; token values are never displayed. |
254
+ | `rcc account remove` | **Local** by default; `POST /api/cli/auth/logout` with `--revoke` | Removes only the named local profile unless `--revoke` is explicitly supplied. |
255
+ | `rcc status` | `GET /api/cli/account` and `GET /api/cli/instances/current` | `account:read`, `instance:read`; combines account, Credits, and current-instance state. |
256
+ | `rcc credits status` | `GET /api/cli/account` | `account:read`; Credits are read-only in RCC. |
257
+ | `rcc catalog list/show/search` | `GET /api/cli/catalog` | `catalog:read`; `show` and `search` filter the returned approved Catalog locally. |
258
+ | `rcc capabilities` | `GET /api/cli/capabilities` | `account:read`; reports enabled and deferred features. |
259
+ | `rcc doctor` | `GET /ready`, `GET /api/cli/auth/status`, and `GET /api/cli/capabilities` | Checks local configuration, transport, token validity, and server contract. |
260
+ | `rcc instance add-key` | `POST /api/cli/ssh-key` | `instance:create`; validates locally and appends only the public key. |
261
+ | `rcc instance create` | `POST /api/cli/instances`, then `GET /api/cli/instances/current` while waiting | `instance:create`, then `instance:read`; SSH is enabled unless `--no-ssh` is passed. |
262
+ | `rcc instance list/status` | `GET /api/cli/instances/current` | `instance:read`; `--all` performs the same account-isolated request for each local profile. |
263
+ | `rcc instance logs` | `GET /api/cli/instances/current/logs` | `logs:read`. |
264
+ | `rcc instance open` | `POST /api/cli/instances/current/open` | `instance:open`; returns a one-time browser handoff. |
265
+ | `rcc instance ssh` | `GET /api/cli/instances/current`, then **local** OpenSSH | `instance:read`; executes `ssh` with the selected account's local private-key path. |
266
+ | `rcc instance delete` | `GET /api/cli/account`, `GET /api/cli/instances/current`, then `DELETE /api/cli/instances/current` | `account:read`, `instance:read`, `instance:delete`; identity and current-instance context are checked before deletion. |
267
+ | `rcc completion SHELL` | **Local** | Generates completion from the same registry used by the parser. |
268
+
269
+ The default `rcc_...` token scopes are:
270
+
271
+ ```text
272
+ account:read
273
+ catalog:read
274
+ instance:read
275
+ instance:create
276
+ instance:delete
277
+ instance:open
278
+ logs:read
279
+ ```
280
+
281
+ The BFF enforces the required scope again for every request. Possessing a token
282
+ does not grant commands outside its recorded scopes.
283
+
284
+ ## Accounts, authentication, and Credits
285
+
286
+ `account` manages local profiles; `auth` manages remote per-device tokens.
287
+
288
+ ```bash
289
+ rcc auth login --account work
290
+ rcc account add personal
291
+ rcc account list
292
+ rcc account current
293
+ rcc account use work
294
+ rcc -A personal status
295
+ rcc -A work auth status
296
+ rcc -A work auth logout
297
+ ```
298
+
299
+ `-A/--account` is an identity boundary. When a named profile is explicitly
300
+ selected, ambient `RCC_URL` and `RCC_TOKEN` credentials for another account are
301
+ ignored. Destructive commands should use `-A NAME` when multiple profiles are
302
+ configured.
303
+
304
+ Environment-based automation may provide a matched pair:
305
+
306
+ ```bash
307
+ export RCC_URL=https://radeon.example.com
308
+ export RCC_TOKEN=rcc_REDACTED
309
+ rcc --output json status
310
+ ```
311
+
312
+ `RCC_TOKEN` requires a matching `RCC_URL`; RCC refuses to guess which Manager
313
+ should receive an ambient token. Command-line `--base-url` and `--token`
314
+ overrides are also available, but passing secrets in command arguments may
315
+ expose them through process inspection or shell history.
316
+
317
+ `rcc auth logout` resolves the same URL/token pair as other commands. If the
318
+ token came from a saved profile, logout revokes it and removes that profile;
319
+ if it came from explicit arguments or the environment, local profiles are kept.
320
+ Environment-only automation can log out without a local profile. A concurrent
321
+ replacement login is preserved when an older token is revoked.
322
+
323
+ Logout does not stop resources, release a GPU, end web sessions, or revoke
324
+ tokens on other devices. `rcc auth logout --all` processes all saved profiles
325
+ and ignores ambient credentials. It cannot be combined with `--account`,
326
+ `--base-url`, or `--token`.
327
+
328
+ Credits are intentionally read-only:
329
+
330
+ ```bash
331
+ rcc credits status
332
+ ```
333
+
334
+ Credit requests and changes remain in the Radeon Cloud web or administrator
335
+ workflow.
336
+
337
+ ## Instance options and behavior
338
+
339
+ Only Catalog-approved Jupyter instances are supported. Creation accepts:
340
+
341
+ - `--env`: approved environment ID, name, or image selector.
342
+ - `--pod-type`: exact resource-pool ID from the Catalog.
343
+ - `--resource-template`: exact resource-template ID from the Catalog.
344
+ - `--disk-size-gb`: optional requested workspace size.
345
+ - `--resource-profile`: optional reviewed resource profile; default `auto`.
346
+ - `--use-pvc` or `--no-pvc`: optional persistence preference.
347
+ - `instance add-key --identity-file`: existing local private key or matching `.pub` path.
348
+ - `--no-ssh`: create without managed SSH.
349
+ - `--idempotency-key`: stable retry key for one logical create operation.
350
+ - `--no-wait`: return after the request is accepted.
351
+ - `--timeout`: local readiness wait limit; default 1800 seconds.
352
+
353
+ The Manager reports a terminal launch failure through current-instance status,
354
+ including while failed gateway resources are being cleaned up. A waiting create
355
+ exits with code `1` and the failure classification. It also stops if the accepted
356
+ instance disappears, is being deleted, or a different instance becomes current.
357
+ Internal Launch Job IDs remain private.
358
+
359
+ A local timeout or Ctrl+C does not cancel server-side work. Recover with:
360
+
361
+ ```bash
362
+ rcc instance status --watch
363
+ rcc instance logs
364
+ ```
365
+
366
+ Use `--interval` and `--timeout` with `instance status --watch` to control local
367
+ polling. Status and logs are always resolved from the authenticated account;
368
+ the SDK cannot supply an arbitrary server-side user name.
369
+
370
+ ## Python SDK
371
+
372
+ Python callers can use the same browser authorization and RCC BFF endpoints:
373
+
374
+ ```python
375
+ from amd_oneclick_sdk import RadeonCloudClient, authenticate
376
+
377
+ manager_url = "https://radeon.example.com"
378
+ login = authenticate(base_url=manager_url, device_name="build-workstation")
379
+ client = RadeonCloudClient(base_url=manager_url, token=login.access_token)
380
+
381
+ print(client.account())
382
+ print(client.capabilities())
383
+ print(client.catalog())
384
+
385
+ created = client.create_instance(
386
+ idempotency_key="provision-notebook-001",
387
+ environment="REVIEWED_ENVIRONMENT",
388
+ pod_type="RESOURCE_POOL",
389
+ resource_template="RESOURCE_TEMPLATE",
390
+ )
391
+ print(created)
392
+ print(client.instance_current())
393
+ ```
394
+
395
+ `OneClickClient` remains available as a compatibility alias.
396
+
397
+ The supported lower-level client methods are:
398
+
399
+ ```text
400
+ start_cli_auth poll_cli_auth
401
+ auth_status auth_logout
402
+ account capabilities catalog
403
+ add_ssh_key create_instance instance_current
404
+ instance_logs
405
+ open_instance delete_instance
406
+ ```
407
+
408
+ Do not print, commit, or embed `AuthResult.access_token` in source code.
409
+
410
+ The Python client uses explicit credentials or a matched `RCC_URL` / `RCC_TOKEN`
411
+ pair (legacy `AMD_ONECLICK_*` aliases also work). It does not load workstation
412
+ profiles automatically. An explicit URL cannot be paired with a token inherited
413
+ from a different environment URL. Passing `token="", require_token=False`
414
+ creates an anonymous client and never inherits an ambient token; browser login
415
+ uses this mode. Explicit named CLI profiles ignore ambient credentials.
416
+
417
+ ## Machine-readable output
418
+
419
+ Put global output options before the command:
420
+
421
+ ```bash
422
+ rcc --output json catalog list
423
+ rcc --output ndjson instance status --watch
424
+ rcc --quiet --output json instance status
425
+ rcc -vv doctor
426
+ ```
427
+
428
+ - `json` writes one final result document to stdout; progress is written to
429
+ stderr.
430
+ - `ndjson` writes event, result, or error documents one per line.
431
+ - Structured documents use `schema_version: rcc.cli/v1` and expose stable
432
+ command fields under `data`.
433
+ - Sensitive fields are redacted. `instance open` is an explicit handoff action,
434
+ so its one-time URL must still be handled as a secret.
435
+ - `completion` is a raw-artifact exception and writes a shell script instead of
436
+ an RCC result envelope.
437
+
438
+ Exit codes:
439
+
440
+ | Code | Meaning |
441
+ |---|---|
442
+ | `0` | The local command completed successfully. |
443
+ | `1` | Manager, network, TLS, protocol, or unexpected local failure. |
444
+ | `2` | Usage, local configuration, or authentication failure. |
445
+ | `5` | Local wait timeout; server-side work may still continue. |
446
+ | `130` | Interrupted by the user; remote work is left unchanged. |
447
+
448
+ A status command can return `0` while reporting a remote lifecycle such as
449
+ `failed` or `none`. Automation must inspect the documented fields under `data`
450
+ as well as the process exit code.
451
+
452
+ `auth status --all` exposes `data.active_account` and `data.accounts` in both
453
+ JSON and NDJSON. `instance status` includes `data.error_code` and `data.detail`
454
+ when the server reports a failure.
455
+
456
+ `doctor` returns `0` with `data.ok=true` only after service health,
457
+ authentication, configuration permissions, and the RCC API v1 contract all
458
+ pass. It requires output schema version 1 and all first-release capabilities.
459
+ Missing tokens, skipped checks, capability errors, and old-server fallbacks
460
+ return `1`; inspect `data.capability_state`, `data.capability_detail`,
461
+ `data.diagnostics`, and `data.remediation`. A successful doctor result must
462
+ still be followed by the actual instance lifecycle validation for that deployment.
463
+
464
+ ## Authentication and security model
465
+
466
+ ```text
467
+ RCC / Python SDK
468
+ -> HTTPS + scoped rcc_ bearer token
469
+ -> Radeon-Cloud-Internal frontend BFF (/api/cli/*)
470
+ -> browser account lookup + derived tenant identity
471
+ -> internal Manager Service API
472
+ -> Kubernetes account-owned Jupyter instance
473
+ ```
474
+
475
+ - The browser continues to use the existing Radeon Cloud login page. The only
476
+ added browser page is the isolated device-authorization confirmation page;
477
+ the existing business SPA, navigation, and pages are unchanged.
478
+ - Raw RCC tokens, polling secrets, and browser codes are not stored by the
479
+ server. Their SHA-256 hashes are stored with token prefix, device name,
480
+ scopes, expiry, and operational metadata.
481
+ - Each token is individually revocable. Account `token_version` changes can
482
+ invalidate all previously issued RCC tokens after a security event.
483
+ - The BFF derives the internal Manager user identity from the authenticated web
484
+ account. A CLI-supplied `user_name` is neither accepted nor trusted.
485
+ - RCC instance responses are allowlisted and exclude internal Launch Job and
486
+ status URLs, SSH public-key material, workload API keys, OpenCode passwords,
487
+ and internal browser-handoff fields. SSH host, port, username, and readiness
488
+ metadata are allowlisted.
489
+ - Authentication, token, and browser-handoff responses use
490
+ `Cache-Control: no-store` where credentials or one-time material may be
491
+ present.
492
+ - TLS verification cannot be disabled from the CLI. Plain HTTP is limited to
493
+ loopback development and the explicitly retained legacy validation endpoint;
494
+ never send a production token over that endpoint.
495
+
496
+ ## Local state
497
+
498
+ | Path | Purpose |
499
+ |---|---|
500
+ | `~/.radeon-cloud/config.json` | Named account profiles, scoped tokens, endpoint, expiry metadata, and the last opaque instance lifecycle fence. |
501
+ | `~/.radeon-cloud/config.json.lock` | Cross-process lock used for atomic profile updates. |
502
+ | `~/.radeon-cloud/keys/NAME/id_ed25519` | Per-account local SSH private key; never uploaded. |
503
+
504
+ On POSIX systems, RCC creates the directory with mode `0700` and the config and
505
+ lock files with mode `0600`. On Windows, store the file in a user-restricted
506
+ directory and verify its ACL separately. Do not commit this configuration or
507
+ copy its token into logs.
508
+
509
+ ## Deferred capabilities
510
+
511
+ The first Radeon-Cloud-Internal integration intentionally does **not** expose:
512
+
513
+ - Registration or registration status.
514
+ - Credit requests.
515
+ - Instance resource sampling over SSH.
516
+ - Launch File, Launch Plan, or public Launch Job commands.
517
+ - Recipe discovery or execution.
518
+ - Serve, ComfyUI, or workload process management.
519
+ - Custom images supplied by the SDK caller.
520
+ - Distill discovery, planning, submission, Runs, logs, artifacts, or cancel.
521
+
522
+ These commands are absent from `rcc --help`, the command registry, and shell
523
+ completion. Their implementation modules and Client HTTP methods are not part
524
+ of this release. The
525
+ Manager may use an internal Launch Job while creating a notebook, but its ID and
526
+ API are not exposed to RCC. `rcc capabilities` reports every deferred feature
527
+ as disabled.
528
+
529
+ ## Server rollout
530
+
531
+ RCC is dark by default. Operators should follow the migration guide at
532
+ [`ops/migrations/rcc-cli/README.md`](../ops/migrations/rcc-cli/README.md):
533
+
534
+ 1. Back up PostgreSQL.
535
+ 2. Apply `001_expand.sql` as the schema owner.
536
+ 3. Apply `002_grant_runtime.sql` as the owner for the frontend role, including
537
+ `SELECT` on `amd_oneclick_schema_versions` as well as the RCC table permissions.
538
+ 4. Run `001_preflight.sql` **as the frontend database role** and require
539
+ `ready=true` with no missing privileges.
540
+ 5. Deploy the frontend BFF and SDK with `RCC_CLI_ENABLED=false`. The Manager
541
+ needs no new configuration: RCC adds no Service API route, alters no frozen
542
+ Service API function or model, and sends no new protocol parameter.
543
+ 6. Verify the edge routes `/api/cli/*` and `/auth/cli/*`.
544
+ 7. Set `RCC_CLI_ENABLED=true` only after those checks succeed.
545
+
546
+ Merging the PR does not apply these manual migrations or enable the feature.
547
+ Then run `rcc doctor` and validate login → Credits/catalog → create/readiness →
548
+ logs → one-time browser opening → deletion/resource release → logout in the
549
+ test deployment before production enablement.
550
+
551
+ Rollback is feature-flag only: set `RCC_CLI_ENABLED=false` and retain the RCC
552
+ tables so issued tokens remain revocable and auditable.
553
+
554
+ ## Troubleshooting
555
+
556
+ ### The browser does not open
557
+
558
+ ```bash
559
+ rcc auth login --no-browser
560
+ ```
561
+
562
+ Open the printed short-lived URL in a trusted browser signed in to the intended
563
+ Radeon Cloud account.
564
+
565
+ ### RCC routes return 404
566
+
567
+ Confirm that the migration is complete, the edge forwards `/api/cli/*` and
568
+ `/auth/cli/*`, and the frontend process has `RCC_CLI_ENABLED=true`.
569
+
570
+ ### An `rc-...` token is rejected
571
+
572
+ This is expected. Run `rcc auth login` to obtain a scoped `rcc_...` resource
573
+ token. Keep the `rc-...` credential only for model forwarding / Token Factory.
574
+
575
+ ### A token expired or was revoked
576
+
577
+ ```bash
578
+ rcc auth login --account NAME
579
+ ```
580
+
581
+ Browser authorization replaces the selected workstation profile with a newly
582
+ issued token.
583
+
584
+ ### Instance creation needs selectors
585
+
586
+ Run `rcc catalog list` first. In a non-interactive shell, pass `--env`,
587
+ `--pod-type`, and `--resource-template` explicitly.
588
+
589
+ ### A local launch wait timed out
590
+
591
+ ```bash
592
+ rcc instance status --watch
593
+ rcc instance logs
594
+ ```
595
+
596
+ The timeout does not cancel the server-side instance creation.
597
+
598
+ ### A ready instance does not open automatically
599
+
600
+ ```bash
601
+ rcc instance open --print
602
+ ```
603
+
604
+ Open the returned URL promptly; it is short-lived and single-use.
605
+
606
+ ## Local regression checks
607
+
608
+ From the repository root, with the repository's test dependencies installed:
609
+
610
+ ```bash
611
+ python3 -m pytest -q tests/test_rcc_frontend.py \
612
+ tests/test_rcc_cli_schema.py tests/test_rcc_migrations.py \
613
+ tests/test_frontend_api_surface.py tests/test_service_api_baseline.py
614
+ ```
615
+
616
+ These cover device authorization and token lifecycle, the RCC schema contract,
617
+ the applied migration under PostgreSQL, the frontend route inventory, and the
618
+ frozen Service API contract. The PostgreSQL check starts and stops an isolated
619
+ socket-only database and never uses an external database URL; it runs when
620
+ PostgreSQL server binaries and `psycopg2` are present and the test user is not
621
+ root, and otherwise reports a skip. The rest use temporary SQLite databases and
622
+ synthetic accounts. None of them allocate GPUs or contact real login providers.
623
+
624
+ ## Project structure
625
+
626
+ ```text
627
+ sdk/
628
+ amd_oneclick_sdk/
629
+ __init__.py # Supported public Python exports
630
+ auth.py # Browser-assisted device authorization
631
+ client.py # RCC BFF HTTP client
632
+ rcc_config.py # Secure local multi-account state
633
+ keys.py # Local SSH key validation and generation
634
+ security.py # URL, TLS, and handoff validation
635
+ cli.py # Public CLI facade
636
+ _cli/ # Command parser, registry, handlers, and output
637
+ linux/ # Linux installer scripts
638
+ windows/ # Windows installer scripts
639
+ pyproject.toml # Package metadata
640
+ README.md # This guide
641
+
642
+ frontend/rcc_routes.py # RCC authentication and resource BFF
643
+ app/cli_auth/ # RCC schema contract and credential persistence
644
+ templates/cli_auth.html # Standalone device-approval page
645
+ ops/migrations/rcc-cli/ # Additive database migration and rollout guide
646
+ ```
647
+
648
+ ## License
649
+
650
+ The SDK package is distributed under the MIT license declared in
651
+ [`pyproject.toml`](pyproject.toml).