@odla-ai/cli 0.36.1 → 0.37.0

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/dist/bin.cjs CHANGED
@@ -838,6 +838,7 @@ var init_admin_ai_auth = __esm({
838
838
  "app:config:write": "apply or inspect one revision-bound configuration operation for an app you own",
839
839
  "platform:runbook:write": "read and edit all of odla's operational runbooks, including admin-visible content",
840
840
  "app:device:enroll": "enrol this machine so it can mint its own short-lived credentials without asking you again",
841
+ "platform:device:enroll:extended": "enrol this machine with a credential that outlives the seven-day owner ceiling \u2014 a durable secret on a machine you are vouching for",
841
842
  "platform:ai:policy:write": "change System AI model routing",
842
843
  "platform:ai:policy:read": "read System AI model routing",
843
844
  "platform:ai:credential:write": "replace a stored AI provider key",
@@ -11184,7 +11185,7 @@ Usage:
11184
11185
  odla-ai security run [target] --ack-redacted-source [--env dev] [--profile odla] [--fail-on high]
11185
11186
  odla-ai security run [target] --self --ack-redacted-source
11186
11187
  odla-ai provision [--live] [--config odla.config.mjs] [--email <odla-account>] [--request-grant] [--no-open] [--wait <seconds>] [--dry-run] [--push-secrets] [--rotate-o11y-token] [--write-dev-vars[=path]] [--yes]
11187
- odla-ai device enroll [--app <id>[,<id>...]] [--name <label>] [--capability <c>[,<c>...]] [--email <odla-account>] [--no-open] [--json]
11188
+ odla-ai device enroll [--app <id>[,<id>...]] [--name <label>] [--capability <c>[,<c>...]] [--device-ttl <30d|6w|2y|forever>] [--email <odla-account>] [--no-open] [--json]
11188
11189
  odla-ai device list [--email <odla-account>] [--json]
11189
11190
  odla-ai device revoke <device-id> [--email <odla-account>] [--json]
11190
11191
  odla-ai credentials list [--config odla.config.mjs] [--env dev] [--all] [--json]
@@ -14546,6 +14547,31 @@ var init_advisory_output = __esm({
14546
14547
  }
14547
14548
  });
14548
14549
 
14550
+ // src/device-ttl.ts
14551
+ function parseDeviceTtl(raw) {
14552
+ if (raw === void 0 || raw === true) return void 0;
14553
+ const text3 = String(raw).trim().toLowerCase();
14554
+ if (!text3) return void 0;
14555
+ if (text3 === "forever" || text3 === "never") return 100 * 365 * DAY_MS;
14556
+ const match = /^(\d+)\s*([dwy])$/.exec(text3);
14557
+ if (!match) {
14558
+ throw new Error(
14559
+ `--device-ttl expects a duration like 30d, 6w, 2y, or "forever" (got "${raw}")`
14560
+ );
14561
+ }
14562
+ return Number(match[1]) * UNITS[match[2]];
14563
+ }
14564
+ var OWNER_DEVICE_TTL_MS, DAY_MS, UNITS;
14565
+ var init_device_ttl = __esm({
14566
+ "src/device-ttl.ts"() {
14567
+ "use strict";
14568
+ init_cjs_shims();
14569
+ OWNER_DEVICE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
14570
+ DAY_MS = 24 * 60 * 60 * 1e3;
14571
+ UNITS = { d: DAY_MS, w: 7 * DAY_MS, y: 365 * DAY_MS };
14572
+ }
14573
+ });
14574
+
14549
14575
  // src/device-command.ts
14550
14576
  async function deviceCommand(parsed, deps) {
14551
14577
  const action2 = parsed.positionals[1] ?? "";
@@ -14562,7 +14588,17 @@ async function enroll(parsed, deps, cfg, doFetch, out, json) {
14562
14588
  const name = stringOpt(parsed.options.name) ?? defaultDeviceName();
14563
14589
  const apps = (stringOpt(parsed.options.app) ?? cfg.app.id).split(",").map((id2) => id2.trim()).filter(Boolean);
14564
14590
  if (apps.length === 0) throw new Error("device enroll needs --app <id>[,<id>\u2026]");
14565
- const token = await scopedToken2(parsed, deps, cfg, doFetch, out, `odla CLI (enroll ${name})`);
14591
+ const deviceTtlMs = parseDeviceTtl(parsed.options["device-ttl"]);
14592
+ const extended = deviceTtlMs !== void 0 && deviceTtlMs > OWNER_DEVICE_TTL_MS;
14593
+ const token = await scopedToken2(
14594
+ parsed,
14595
+ deps,
14596
+ cfg,
14597
+ doFetch,
14598
+ out,
14599
+ `odla CLI (enroll ${name})`,
14600
+ extended ? "platform:device:enroll:extended" : "app:device:enroll"
14601
+ );
14566
14602
  const response2 = await doFetch(`${cfg.platformUrl}/registry/devices`, {
14567
14603
  method: "POST",
14568
14604
  headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
@@ -14570,7 +14606,8 @@ async function enroll(parsed, deps, cfg, doFetch, out, json) {
14570
14606
  name,
14571
14607
  platform: import_node_process15.default.platform,
14572
14608
  appIds: apps,
14573
- ...parsed.options.capability ? { capabilities: String(parsed.options.capability).split(",").map((c) => c.trim()).filter(Boolean) } : {}
14609
+ ...parsed.options.capability ? { capabilities: String(parsed.options.capability).split(",").map((c) => c.trim()).filter(Boolean) } : {},
14610
+ ...deviceTtlMs === void 0 ? {} : { deviceTtlMs }
14574
14611
  })
14575
14612
  });
14576
14613
  const body = await response2.json().catch(() => ({}));
@@ -14623,12 +14660,12 @@ async function revoke(parsed, deps, cfg, doFetch, out, json) {
14623
14660
  out.error(`device: revoked ${deviceId}; every credential it minted is revoked with it`);
14624
14661
  if (json) out.log(JSON.stringify({ deviceId, revoked: true }, null, 2));
14625
14662
  }
14626
- async function scopedToken2(parsed, deps, cfg, doFetch, out, label) {
14663
+ async function scopedToken2(parsed, deps, cfg, doFetch, out, label, scope = "app:device:enroll") {
14627
14664
  const { credentials } = await resolveOperatorContext(parsed, { allowMissingConfig: true });
14628
14665
  const scopedTokenFile = credentials.scopedTokenFile;
14629
14666
  return getScopedPlatformToken({
14630
14667
  platform: cfg.platformUrl,
14631
- scope: "app:device:enroll",
14668
+ scope,
14632
14669
  email: stringOpt(parsed.options.email),
14633
14670
  label,
14634
14671
  fetch: doFetch,
@@ -14648,6 +14685,7 @@ var init_device_command = __esm({
14648
14685
  "src/device-command.ts"() {
14649
14686
  "use strict";
14650
14687
  init_cjs_shims();
14688
+ init_device_ttl();
14651
14689
  import_node_fs20 = require("fs");
14652
14690
  import_node_path18 = require("path");
14653
14691
  import_node_process15 = __toESM(require("process"), 1);