@ornncompute/cli 0.1.6 → 0.1.8

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.
package/README.md CHANGED
@@ -56,11 +56,14 @@ ornn nodes keys list <node-id> [--json]
56
56
  ornn node health <node-id> [--json]
57
57
  ornn node diagnose <node-id> [--json]
58
58
  ornn node deenroll <node-id> [--reason <text>] [--keep-record] [--json]
59
- ornn fleet clean <ip>... --operator <id-or-slug> --ib-island <name> --identity-file <path> --dry-run [--source-user <user>]... [--preserve-user <user>]... [--ssh-user ubuntu|admin|ornn] [--json]
60
- ornn fleet clean <failed-fleet-id> --identity-file <path> --dry-run [--source-user <user>]... [--preserve-user <user>]... [--json]
61
- ornn fleet clean <fleet-id> --identity-file <path> --confirm-clean <plan-hash> [--source-user <user>]... [--preserve-user <user>]... [--json]
59
+ ornn fleet clean <ip>... --operator <id-or-slug> --ib-island <name> --identity-file <path> --dry-run [--policy <path>] [--policy-out <path>] [--ssh-user ubuntu|admin|ornn] [--json]
60
+ ornn fleet clean <fleet-id> --identity-file <path> --dry-run [--policy <path>] [--policy-out <path>] [--json]
61
+ ornn fleet clean <fleet-id> --identity-file <path> --confirm-clean <plan-hash> [--json]
62
62
  ornn fleet enroll <fleet-id> --identity-file <path> [--confirm-takeover <ip[,ip...]>] [--json]
63
- ornn fleet deploy <fleet-id> --tenant <contact-email> --user <email-or-id> [--commerce-reservation <id>] [--network public|private] [--json]
63
+ ornn fleet delete <fleet-id> --confirm-delete <fleet-id> [--json]
64
+ ornn reservations commerce list --tenant <email-or-id> [--fleet <fleet-id>] [--json]
65
+ ornn reservations commerce create --tenant <email> --listing <listing-id> --fleet <fleet-id> [--start-at <timestamp>] [--end-at <timestamp>] [--price-per-gpu-hour <rate>] [--json]
66
+ ornn fleet deploy <fleet-id> --tenant <contact-email> [--user <email-or-id>] --commerce-reservation <id> [--network public|private] [--json]
64
67
  ornn ssh <node-or-reservation-id> [--print] [--identity-file <path>] [--user <name>] [--json]
65
68
  ornn metrics nodes [--json]
66
69
  ornn metrics node <node-id> [--json]
@@ -103,9 +106,9 @@ ornn storage volumes create --name <name> [--source <drive-id>] [--json]
103
106
  ornn storage volumes refresh <drive-id> [--json]
104
107
  ornn storage volumes clear <drive-id> [--json]
105
108
  ornn storage volumes delete <drive-id> [--json]
106
- ornn storage deploy <drive-id> --reservation <reservation-id> [--mount-path <path>] [--read-only|--read-write] [--json]
109
+ ornn storage files upload <drive-id> <local-file> [--destination <path>] [--content-type <type>] [--json]
110
+ ornn storage deploy <drive-id> --reservation <reservation-id> [--all-nodes] [--mount-path <path>] [--read-only|--read-write] [--json]
107
111
  ornn storage deploy status --reservation <reservation-id> [--json]
108
- ornn storage unmount --reservation <reservation-id> [--json]
109
112
  ornn storage undeploy --reservation <reservation-id> [--json]
110
113
  ornn storage buckets list [--json]
111
114
  ornn storage buckets show <drive-id> [--json]
@@ -143,8 +146,23 @@ current user's complete reservation key set on those machines. Use
143
146
  `ornn access keys push` to explicitly re-sync keys that are already attached.
144
147
 
145
148
  `ornn storage deploy status` prints reconciled object and byte progress once the
146
- managed transfer has reported progress. AWS S3 and external GCS sources use the
147
- managed transfer path. Cloudflare R2 support is coming soon.
149
+ managed transfer has reported progress, plus the number of target nodes that
150
+ have acknowledged the mount. Internal placement bucket details are not shown.
151
+ AWS S3 and external GCS sources use the managed transfer path. Cloudflare R2
152
+ buckets can be connected and verified, but deployment support is coming soon.
153
+
154
+ `ornn storage files upload` adds a file to the drive's current colocated copy.
155
+ You can upload while a direct FUSE mount is active; every mounted node sees the
156
+ file on its next lookup without a remount. A direct FUSE drive attaches to one
157
+ reservation by default; pass `--all-nodes` on `ornn storage deploy` to fan the
158
+ same mount out across every compatible node in the node group. Avoid writing
159
+ the same file path concurrently from multiple nodes because object storage is
160
+ not a POSIX shared filesystem.
161
+
162
+ For a connected bucket, deploy once before uploading. The first deploy imports
163
+ the source into an Ornn-managed colocated working copy. That copy remains the
164
+ drive's durable data when you unmount, detach, or mount it elsewhere. Ornn
165
+ does not write changes back to the original connected bucket.
148
166
 
149
167
  UI aliases are first-class in the CLI: `listings` maps to the older
150
168
  `availability` command, `exchange` maps to `bid`, and `gpus` maps to
@@ -200,7 +218,7 @@ The operator resource commands share the same reviewer auth:
200
218
  filtered to one operator.
201
219
  - `ornn tokens list` lists enrollment tokens.
202
220
  - `ornn tokens create --operator <id> [--facility <id>]
203
- [--expires-in <seconds>] [--mode bare-metal|vm] [--ip <addr>]` mints an
221
+ [--expires-in <seconds>] [--mode bare-metal|vm] [--ip <addr>]` mints an
204
222
  enrollment token and prints a ready-to-run `curl … | sudo bash` install
205
223
  command.
206
224
  - `ornn tokens revoke <token-id>` revokes an enrollment token.
@@ -210,33 +228,72 @@ Fleet handoff is an ordered, Compute-backed workflow:
210
228
  - Before first contact, independently verify each host key and add it to the
211
229
  operator's SSH `known_hosts`; fleet SSH uses strict host-key checking and will
212
230
  not trust a key first presented during cleanup.
213
- - `fleet clean ... --dry-run` tries `ubuntu`, `admin`, then `ornn`, records each
214
- host's hardware identity and exact deletion plan, and prints one fleet plan
215
- hash. Repeat `--source-user` for Linux accounts owned by the departing tenant
216
- (including an explicitly reviewed orphaned `/home/<user>` directory) and
217
- `--preserve-user` for reviewed host accounts. Package/service-owned
218
- accounts are protected automatically; any other account stops planning for
219
- explicit review. Re-running with `--confirm-clean <plan-hash>` and the same
220
- account flags removes the approved tenant
221
- users, keys, containers/images/volumes/networks/build cache, workload paths,
222
- mounts, services, and tenant-scoped logs. Apply refuses plans with running
223
- containers, locks the management/root passwords, enforces key-only SSH, trims
224
- supported filesystems, preserves existing root and management keys and host
225
- logs, and stores per-node proof in Compute. A failed
226
- cleanup can be dry-run again with the same fleet ID; only failed members are
227
- replanned. Residual GPU
228
- consumers or tenant/platform listeners fail verification instead of being
229
- silently accepted.
231
+ - `fleet clean ... --dry-run` tries `ubuntu`, `admin`, then `ornn`, binds the
232
+ inventory to the host's hardware identity, records the plan in Compute, and
233
+ writes an editable mode-`0600` policy beside the local fleet manifest (or to
234
+ `--policy-out`). Inventory covers accounts and orphan homes, authorized SSH
235
+ keys, tenant/log/temp/platform paths, workload and listener processes, GPU
236
+ consumers, custom systemd services, Docker/Podman objects and bind-mount
237
+ dependencies, and every block drive. Each resource advertises its own valid
238
+ actions. Suggestions are never applied silently: unresolved choices and
239
+ conflicts are recorded as plan data, so edit the policy and re-run the same
240
+ fleet with `--policy`; planning is not terminalized just because a choice is
241
+ needed. `--source-user` and `--preserve-user` remain legacy user-only
242
+ shortcuts and cannot be mixed with a policy file.
243
+ - `fleet clean <fleet-id> ... --confirm-clean <plan-hash>` is shown only after
244
+ every choice is resolved. Execution rechecks hardware and resource identity,
245
+ runs an idempotent per-resource journal, preserves the management SSH key,
246
+ enforces key-only SSH, and returns exact deleted, preserved, exception, and
247
+ drive-assurance evidence. `ignore` requires a reason and produces
248
+ `clean_with_exceptions`; it is never reported as residue-free deletion.
249
+ Data-drive actions are selectable: `logical_clean`, `discard`, `sanitize`, or
250
+ `reformat`. The system drive and drives without a unique serial/WWN are
251
+ locked to keep/ignore for in-band cleanup. `sanitize` requires NVMe plus
252
+ controller-reported completion. Logical cleanup, discard, and reformat are
253
+ not certified physical-media erasure, and the system drive requires an
254
+ out-of-band reimage for that assurance.
255
+ If the local SSH command times out while a long device operation is still in
256
+ progress, the recorded run remains resumable; re-run the same
257
+ `--confirm-clean <plan-hash>` command instead of creating a different plan.
258
+ Plans created by a pre-v6 runner must be replanned with `--dry-run` before
259
+ approval. This keeps newly discovered resources bound to a fresh reviewed
260
+ hash instead of adapting a legacy account-only plan during execution.
261
+
262
+ In the generated policy, change only `action`, plus `reason` for `ignore` or
263
+ `replacement` for `replace`; keep each generated `identity_hash` intact. `keep`
264
+ leaves a resource running, `stop_keep` stops but retains it, `stop` terminates a
265
+ process, `delete` removes it, `restart` restarts a service, and `replace`
266
+ recreates a container from the supplied image/name/network/command/labels/mounts
267
+ specification. The generated `suggested_action` is review guidance, not an
268
+ automatic decision. Do not put secrets in replacement commands or labels; use
269
+ the platform secret manager or a reviewed secret mount.
270
+
230
271
  - `fleet enroll <fleet-id>` refuses nodes without successful cleanup proof,
231
272
  issues and revokes one cleanup-bound token per host, installs the agent,
232
273
  assigns the IB island, verifies the same management account still has
233
274
  key-based SSH and passwordless sudo, and records the resulting GPU node IDs
234
275
  in Compute. Generic enrollment tokens retain the legacy enrollment sanitizer.
235
- - `fleet deploy <fleet-id> --tenant <contact-email> --user <email-or-id>
236
- [--commerce-reservation <id>]` validates the exact tenant/user and, when
237
- supplied, the Commerce reservation. It succeeds only after every selected
238
- user's SSH key is installed on every running node and passwordless sudo is
239
- reported ready.
276
+ - `fleet delete <fleet-id> --confirm-delete <fleet-id>` hard-deletes only an
277
+ abandoned cleanup plan or an unassigned legacy enrollment record. It saves a
278
+ local audit manifest first and refuses any Commerce/tenant/deployment link,
279
+ active enrollment, assigned GPU node, or completed/running cleanup evidence.
280
+ It never deletes the linked GPU-node records.
281
+ - `reservations commerce create --tenant <email> --listing <listing-id>
282
+ --fleet <fleet-id>` creates and activates the tenant's Commerce reservation.
283
+ GPU count comes from the enrolled fleet; start, end, and hourly rate default
284
+ from the listing. Start and end overrides must remain inside the listing's
285
+ allowed window; the hourly rate can also be overridden explicitly.
286
+ - `reservations commerce list --tenant <email-or-id> [--fleet <fleet-id>]`
287
+ lists active reservations in their live window; with `--fleet`, it returns
288
+ only reservations whose listing exactly matches that fleet's operator,
289
+ facility, GPU model, per-node size, and total GPU count.
290
+ - `fleet deploy <fleet-id> --tenant <contact-email>
291
+ [--user <email-or-id>] --commerce-reservation <id>` requires a live,
292
+ tenant-owned Commerce reservation whose listing exactly matches the fleet.
293
+ The user defaults to the tenant's primary administrator. Deployment succeeds
294
+ only after that user's SSH access and passwordless sudo are ready on every
295
+ node; Commerce is stamped only after the entire fleet reports deployed. A
296
+ Commerce reservation can be linked to only one fleet.
240
297
 
241
298
  Compute Postgres is authoritative; the mode-0600 files under
242
299
  `~/.config/ornn/fleets/` are only a secret-free cache. Cleanup proves “no
@@ -248,17 +305,22 @@ control-plane policy.
248
305
 
249
306
  Reservation lifecycle verbs also run under the operator surface:
250
307
 
308
+ - `ornn reservations commerce create|list` creates or discovers a validated
309
+ Commerce reservation for an enrolled fleet. These actions require a staff
310
+ `ornn login`; the direct review-secret path cannot bypass Web validation.
251
311
  - `ornn reservations withdraw <reservation-id>` withdraws a reservation's
252
312
  acceptance, returning the node(s) to tenant inventory.
253
313
  - `ornn reservations transfer <reservation-id> --target-tenant <id>
254
- [--target-user <id>] [--node <id>] [--strategy reject|park] [--confirm]`
314
+ [--target-user <id>] [--node <id>] [--strategy reject|park] [--confirm]`
255
315
  transfers a reservation to another tenant.
256
- - `ornn reservations deploy <node-id> --target-tenant <id> [--target-user <id>]
257
- [--network public|private]` deploys a node into a tenant's inventory.
316
+ - `ornn reservations deploy <node-id> --target-tenant <id>
317
+ --commerce-reservation <id> [--target-user <id>] [--network public|private]`
318
+ deploys one node only after Web verifies that the live tenant-owned Commerce
319
+ reservation and listing match that node.
258
320
 
259
321
  The tenant `ornn reservations list|show|checkout` verbs still use the tenant CLI
260
- login and `/api/cli` proxy; `withdraw|transfer|deploy` use the operator path
261
- above (staff session proxy or optional review secret).
322
+ login and `/api/cli` proxy. Staff Commerce actions use the Web operator proxy;
323
+ `withdraw|transfer|deploy` retain the operator path above.
262
324
 
263
325
  Staff happy path:
264
326
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ornncompute/cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Command-line interface for Ornn compute access workflows.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -271,6 +271,28 @@ export async function operatorRequest({
271
271
  );
272
272
  }
273
273
 
274
+ /**
275
+ * Commerce-backed operator actions must cross the Web trust boundary. Web
276
+ * validates Commerce state before it forwards to Compute, so direct
277
+ * review-secret access is intentionally unavailable for these requests.
278
+ */
279
+ export async function webOperatorRequest({
280
+ body,
281
+ endpoint,
282
+ env = process.env,
283
+ fetchImpl = fetch,
284
+ method = "GET",
285
+ } = {}) {
286
+ const session = await loadAuthSession({ env });
287
+ if (!session?.accessToken) {
288
+ throw new CliApiError(
289
+ "Commerce-backed deployment requires Ornn staff auth through Web. Run `ornn login` first.",
290
+ { status: 401 },
291
+ );
292
+ }
293
+ return operatorRequestViaStaffSession({ body, endpoint, env, fetchImpl, method });
294
+ }
295
+
274
296
  export function computeEndpoint(path) {
275
297
  const normalized = normalizeComputePath(path);
276
298
  return `/api/cli/compute${normalized}`;
@@ -341,6 +363,9 @@ function detailMessage(detail) {
341
363
  if (!detail || typeof detail !== "object") {
342
364
  return "";
343
365
  }
366
+ if (typeof detail.message === "string") {
367
+ return detail.message;
368
+ }
344
369
  if (typeof detail.summary === "string") {
345
370
  return detail.summary;
346
371
  }