@odla-ai/cli 0.36.0 → 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 +46 -7
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-DBZQIMES.js → chunk-OWTIDSL5.js} +39 -8
- package/dist/chunk-OWTIDSL5.js.map +1 -0
- package/dist/{cli-BN6WLH5O.js → cli-QR44X5IB.js} +2 -2
- package/dist/index.cjs +38 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-DBZQIMES.js.map +0 -1
- /package/dist/{cli-BN6WLH5O.js.map → cli-QR44X5IB.js.map} +0 -0
package/dist/bin.js
CHANGED
|
@@ -174,7 +174,7 @@ function absoluteEntryPath(entryPath) {
|
|
|
174
174
|
|
|
175
175
|
// src/bin.ts
|
|
176
176
|
var argv = process.argv.slice(2);
|
|
177
|
-
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-
|
|
177
|
+
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-QR44X5IB.js")).runCli()).catch((err) => {
|
|
178
178
|
console.error(redactSecrets(`odla-ai: ${err instanceof Error ? err.message : String(err)}`));
|
|
179
179
|
process.exitCode = exitCodeFor(err);
|
|
180
180
|
});
|
|
@@ -200,9 +200,10 @@ async function mintDeviceSession(platformUrl, credential2, doFetch) {
|
|
|
200
200
|
});
|
|
201
201
|
const body = await response2.json().catch(() => ({}));
|
|
202
202
|
if (!response2.ok || typeof body.token !== "string") {
|
|
203
|
-
const
|
|
203
|
+
const revocable = response2.status === 401 || response2.status === 403 || response2.status === 404;
|
|
204
|
+
const detail = body.error?.message ?? (response2.ok ? `registry returned ${response2.status} with no session token` : `registry returned ${response2.status}`);
|
|
204
205
|
throw new Error(
|
|
205
|
-
`device session failed: ${detail} (${response2.status}) \u2014 if this machine's enrollment was revoked or has expired, enroll it again in Studio
|
|
206
|
+
`device session failed: ${detail} (${response2.status})` + (revocable ? " \u2014 if this machine's enrollment was revoked or has expired, enroll it again in Studio" : "")
|
|
206
207
|
);
|
|
207
208
|
}
|
|
208
209
|
return { token: body.token, expiresAt: body.expiresAt ?? Date.now() };
|
|
@@ -550,6 +551,7 @@ var SCOPE_PURPOSE = {
|
|
|
550
551
|
"app:config:write": "apply or inspect one revision-bound configuration operation for an app you own",
|
|
551
552
|
"platform:runbook:write": "read and edit all of odla's operational runbooks, including admin-visible content",
|
|
552
553
|
"app:device:enroll": "enrol this machine so it can mint its own short-lived credentials without asking you again",
|
|
554
|
+
"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",
|
|
553
555
|
"platform:ai:policy:write": "change System AI model routing",
|
|
554
556
|
"platform:ai:policy:read": "read System AI model routing",
|
|
555
557
|
"platform:ai:credential:write": "replace a stored AI provider key",
|
|
@@ -10286,7 +10288,7 @@ Usage:
|
|
|
10286
10288
|
odla-ai security run [target] --ack-redacted-source [--env dev] [--profile odla] [--fail-on high]
|
|
10287
10289
|
odla-ai security run [target] --self --ack-redacted-source
|
|
10288
10290
|
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]
|
|
10289
|
-
odla-ai device enroll [--app <id>[,<id>...]] [--name <label>] [--capability <c>[,<c>...]] [--email <odla-account>] [--no-open] [--json]
|
|
10291
|
+
odla-ai device enroll [--app <id>[,<id>...]] [--name <label>] [--capability <c>[,<c>...]] [--device-ttl <30d|6w|2y|forever>] [--email <odla-account>] [--no-open] [--json]
|
|
10290
10292
|
odla-ai device list [--email <odla-account>] [--json]
|
|
10291
10293
|
odla-ai device revoke <device-id> [--email <odla-account>] [--json]
|
|
10292
10294
|
odla-ai credentials list [--config odla.config.mjs] [--env dev] [--all] [--json]
|
|
@@ -13377,6 +13379,24 @@ function renderAdvisories(out, advisories, env = process.env) {
|
|
|
13377
13379
|
}
|
|
13378
13380
|
}
|
|
13379
13381
|
|
|
13382
|
+
// src/device-ttl.ts
|
|
13383
|
+
var OWNER_DEVICE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
13384
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
13385
|
+
var UNITS = { d: DAY_MS, w: 7 * DAY_MS, y: 365 * DAY_MS };
|
|
13386
|
+
function parseDeviceTtl(raw) {
|
|
13387
|
+
if (raw === void 0 || raw === true) return void 0;
|
|
13388
|
+
const text3 = String(raw).trim().toLowerCase();
|
|
13389
|
+
if (!text3) return void 0;
|
|
13390
|
+
if (text3 === "forever" || text3 === "never") return 100 * 365 * DAY_MS;
|
|
13391
|
+
const match = /^(\d+)\s*([dwy])$/.exec(text3);
|
|
13392
|
+
if (!match) {
|
|
13393
|
+
throw new Error(
|
|
13394
|
+
`--device-ttl expects a duration like 30d, 6w, 2y, or "forever" (got "${raw}")`
|
|
13395
|
+
);
|
|
13396
|
+
}
|
|
13397
|
+
return Number(match[1]) * UNITS[match[2]];
|
|
13398
|
+
}
|
|
13399
|
+
|
|
13380
13400
|
// src/device-command.ts
|
|
13381
13401
|
import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
13382
13402
|
import { dirname as dirname10 } from "path";
|
|
@@ -13396,7 +13416,17 @@ async function enroll(parsed, deps, cfg, doFetch, out, json) {
|
|
|
13396
13416
|
const name = stringOpt(parsed.options.name) ?? defaultDeviceName();
|
|
13397
13417
|
const apps = (stringOpt(parsed.options.app) ?? cfg.app.id).split(",").map((id2) => id2.trim()).filter(Boolean);
|
|
13398
13418
|
if (apps.length === 0) throw new Error("device enroll needs --app <id>[,<id>\u2026]");
|
|
13399
|
-
const
|
|
13419
|
+
const deviceTtlMs = parseDeviceTtl(parsed.options["device-ttl"]);
|
|
13420
|
+
const extended = deviceTtlMs !== void 0 && deviceTtlMs > OWNER_DEVICE_TTL_MS;
|
|
13421
|
+
const token = await scopedToken2(
|
|
13422
|
+
parsed,
|
|
13423
|
+
deps,
|
|
13424
|
+
cfg,
|
|
13425
|
+
doFetch,
|
|
13426
|
+
out,
|
|
13427
|
+
`odla CLI (enroll ${name})`,
|
|
13428
|
+
extended ? "platform:device:enroll:extended" : "app:device:enroll"
|
|
13429
|
+
);
|
|
13400
13430
|
const response2 = await doFetch(`${cfg.platformUrl}/registry/devices`, {
|
|
13401
13431
|
method: "POST",
|
|
13402
13432
|
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
@@ -13404,7 +13434,8 @@ async function enroll(parsed, deps, cfg, doFetch, out, json) {
|
|
|
13404
13434
|
name,
|
|
13405
13435
|
platform: process16.platform,
|
|
13406
13436
|
appIds: apps,
|
|
13407
|
-
...parsed.options.capability ? { capabilities: String(parsed.options.capability).split(",").map((c) => c.trim()).filter(Boolean) } : {}
|
|
13437
|
+
...parsed.options.capability ? { capabilities: String(parsed.options.capability).split(",").map((c) => c.trim()).filter(Boolean) } : {},
|
|
13438
|
+
...deviceTtlMs === void 0 ? {} : { deviceTtlMs }
|
|
13408
13439
|
})
|
|
13409
13440
|
});
|
|
13410
13441
|
const body = await response2.json().catch(() => ({}));
|
|
@@ -13457,12 +13488,12 @@ async function revoke(parsed, deps, cfg, doFetch, out, json) {
|
|
|
13457
13488
|
out.error(`device: revoked ${deviceId}; every credential it minted is revoked with it`);
|
|
13458
13489
|
if (json) out.log(JSON.stringify({ deviceId, revoked: true }, null, 2));
|
|
13459
13490
|
}
|
|
13460
|
-
async function scopedToken2(parsed, deps, cfg, doFetch, out, label) {
|
|
13491
|
+
async function scopedToken2(parsed, deps, cfg, doFetch, out, label, scope = "app:device:enroll") {
|
|
13461
13492
|
const { credentials } = await resolveOperatorContext(parsed, { allowMissingConfig: true });
|
|
13462
13493
|
const scopedTokenFile = credentials.scopedTokenFile;
|
|
13463
13494
|
return getScopedPlatformToken({
|
|
13464
13495
|
platform: cfg.platformUrl,
|
|
13465
|
-
scope
|
|
13496
|
+
scope,
|
|
13466
13497
|
email: stringOpt(parsed.options.email),
|
|
13467
13498
|
label,
|
|
13468
13499
|
fetch: doFetch,
|
|
@@ -15265,4 +15296,4 @@ export {
|
|
|
15265
15296
|
isTerminalHostedSecurityStatus,
|
|
15266
15297
|
runCli
|
|
15267
15298
|
};
|
|
15268
|
-
//# sourceMappingURL=chunk-
|
|
15299
|
+
//# sourceMappingURL=chunk-OWTIDSL5.js.map
|