@m8t-stack/cli 0.2.63 → 0.2.64
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/cli.js +110 -30
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1364,7 +1364,7 @@ var init_enable_hosted_brain = __esm({
|
|
|
1364
1364
|
import { Builtins, Cli } from "clipanion";
|
|
1365
1365
|
|
|
1366
1366
|
// src/lib/package-version.ts
|
|
1367
|
-
var CLI_VERSION = "0.2.
|
|
1367
|
+
var CLI_VERSION = "0.2.64";
|
|
1368
1368
|
|
|
1369
1369
|
// src/lib/render-error.ts
|
|
1370
1370
|
init_errors();
|
|
@@ -19006,15 +19006,35 @@ import { DefaultAzureCredential as DefaultAzureCredential16 } from "@azure/ident
|
|
|
19006
19006
|
init_errors();
|
|
19007
19007
|
var DEFAULT_IMAGE_REPO = "ghcr.io/m8t-labs/m8t";
|
|
19008
19008
|
function parseImageRef2(ref) {
|
|
19009
|
-
|
|
19010
|
-
|
|
19011
|
-
|
|
19009
|
+
let rest = ref;
|
|
19010
|
+
let digest;
|
|
19011
|
+
const at = rest.lastIndexOf("@");
|
|
19012
|
+
if (at !== -1) {
|
|
19013
|
+
digest = rest.slice(at + 1) || void 0;
|
|
19014
|
+
rest = rest.slice(0, at);
|
|
19015
|
+
}
|
|
19016
|
+
const lastColon = rest.lastIndexOf(":");
|
|
19017
|
+
const lastSlash = rest.lastIndexOf("/");
|
|
19018
|
+
let name = rest;
|
|
19012
19019
|
let tag;
|
|
19013
19020
|
if (lastColon > lastSlash) {
|
|
19014
|
-
name =
|
|
19015
|
-
tag =
|
|
19021
|
+
name = rest.slice(0, lastColon);
|
|
19022
|
+
tag = rest.slice(lastColon + 1) || void 0;
|
|
19016
19023
|
}
|
|
19017
|
-
return { registry: name.split("/")[0], repo: name, tag };
|
|
19024
|
+
return { registry: name.split("/")[0], repo: name, tag, digest };
|
|
19025
|
+
}
|
|
19026
|
+
function assertGatewayDigest(c) {
|
|
19027
|
+
if (!c.digest?.startsWith("sha256:")) {
|
|
19028
|
+
throw new LocalCliError({
|
|
19029
|
+
code: "PLATFORM_GATEWAY_DIGEST_MISSING",
|
|
19030
|
+
message: `The release manifest's gateway pin (${c.ref}:${c.tag}) carries no usable image digest.`,
|
|
19031
|
+
hint: "Re-fetch the release channel, or target a release whose manifest pins a gateway digest. Deploying by tag instead is not offered: a mutable tag cannot establish which bytes run."
|
|
19032
|
+
});
|
|
19033
|
+
}
|
|
19034
|
+
return c.digest;
|
|
19035
|
+
}
|
|
19036
|
+
function gatewayRefFromComponent(c) {
|
|
19037
|
+
return `${c.ref}@${assertGatewayDigest(c)}`;
|
|
19018
19038
|
}
|
|
19019
19039
|
var SEMVER_TAG = /^v(\d+)\.(\d+)\.(\d+)$/;
|
|
19020
19040
|
function isSemverTag(tag) {
|
|
@@ -19058,7 +19078,7 @@ function parseContainerAppResourceId(id) {
|
|
|
19058
19078
|
}
|
|
19059
19079
|
function planUpdate(opts) {
|
|
19060
19080
|
const cur = parseImageRef2(opts.currentImage);
|
|
19061
|
-
const currentTag = cur.tag ?? "(none)";
|
|
19081
|
+
const currentTag = cur.tag ?? cur.digest ?? "(none)";
|
|
19062
19082
|
if (cur.repo !== opts.imageRepo) {
|
|
19063
19083
|
return { kind: "refuse-byoc", current: currentTag, currentRepo: cur.repo, trackedRepo: opts.imageRepo };
|
|
19064
19084
|
}
|
|
@@ -19067,6 +19087,9 @@ function planUpdate(opts) {
|
|
|
19067
19087
|
}
|
|
19068
19088
|
const available = opts.to ?? pickNewestSemver(opts.availableTags);
|
|
19069
19089
|
if (!available) return { kind: "no-versions", current: currentTag };
|
|
19090
|
+
if (cur.digest && opts.toDigest && cur.digest === opts.toDigest) {
|
|
19091
|
+
return { kind: "noop", current: currentTag, available };
|
|
19092
|
+
}
|
|
19070
19093
|
if (cur.tag === available) return { kind: "noop", current: currentTag, available };
|
|
19071
19094
|
if (!opts.to) {
|
|
19072
19095
|
const currentIsSemver = cur.tag ? isSemverTag(cur.tag) : false;
|
|
@@ -20057,14 +20080,14 @@ async function applyGatewayImage(a, ctx, gatewayResourceId) {
|
|
|
20057
20080
|
const { resourceGroup, name } = parseContainerAppResourceId(gatewayResourceId);
|
|
20058
20081
|
const current = (await runAz(["containerapp", "show", "-g", resourceGroup, "-n", name, "--query", "properties.template.containers[0].image", "-o", "tsv"])).trim();
|
|
20059
20082
|
const tags = await fetchPublicTags(DEFAULT_IMAGE_REPO);
|
|
20060
|
-
const plan = planUpdate({ currentImage: current, availableTags: tags, imageRepo: DEFAULT_IMAGE_REPO, to: a.to });
|
|
20061
20083
|
const digest = ctx.manifest.components.gateway.digest;
|
|
20084
|
+
const plan = planUpdate({ currentImage: current, availableTags: tags, imageRepo: DEFAULT_IMAGE_REPO, to: a.to, toDigest: digest });
|
|
20062
20085
|
switch (plan.kind) {
|
|
20063
20086
|
case "refuse-byoc":
|
|
20064
20087
|
ctx.onProgress?.(`gateway is BYOC (${plan.currentRepo}) \u2014 marking externally managed.`);
|
|
20065
20088
|
return { tag: a.to, digest, state: "external" };
|
|
20066
20089
|
case "roll":
|
|
20067
|
-
await runAz(["containerapp", "update", "-n", name, "-g", resourceGroup, "--image", `${plan.repo}
|
|
20090
|
+
await runAz(["containerapp", "update", "-n", name, "-g", resourceGroup, "--image", `${plan.repo}@${assertGatewayDigest(ctx.manifest.components.gateway)}`]);
|
|
20068
20091
|
return { tag: a.to, digest, state: "managed" };
|
|
20069
20092
|
case "noop":
|
|
20070
20093
|
return { tag: a.to, digest, state: "managed" };
|
|
@@ -20107,7 +20130,7 @@ async function resolveBicepParamsForConverge(ctx, opts = {}) {
|
|
|
20107
20130
|
const location = opts.location ?? (await runAz(["resource", "list", "-g", ctx.resourceGroup, "--query", "[0].location", "-o", "tsv"])).trim();
|
|
20108
20131
|
const foundryResourceId = await resolveFoundryResourceId(opts.foundryEndpoint ?? "", opts.foundryResourceId);
|
|
20109
20132
|
const acrPullIdentityResourceId = resolveAcrPullIdentity({ explicit: opts.acrPullIdentity });
|
|
20110
|
-
const imageRef =
|
|
20133
|
+
const imageRef = gatewayRefFromComponent(ctx.manifest.components.gateway);
|
|
20111
20134
|
const acrResourceId = await resolveAcrResourceId({ imageRef, explicit: opts.acrResourceId });
|
|
20112
20135
|
return {
|
|
20113
20136
|
location,
|
|
@@ -20243,6 +20266,57 @@ async function applyPersona(a, ctx, opts) {
|
|
|
20243
20266
|
return { treeSha: a.to, foundryVersion };
|
|
20244
20267
|
}
|
|
20245
20268
|
|
|
20269
|
+
// src/lib/gateway-verify.ts
|
|
20270
|
+
function compareGatewayBinding(args) {
|
|
20271
|
+
const base = { stampTag: args.stampTag, stampDigest: args.stampDigest };
|
|
20272
|
+
if (!args.liveImage) {
|
|
20273
|
+
return { ...base, live: { kind: "unread" }, comparedBy: "none", match: "unknown" };
|
|
20274
|
+
}
|
|
20275
|
+
const parsed = parseImageRef2(args.liveImage);
|
|
20276
|
+
if (parsed.digest) {
|
|
20277
|
+
const comparable = Boolean(args.stampDigest);
|
|
20278
|
+
return {
|
|
20279
|
+
...base,
|
|
20280
|
+
live: { kind: "digest", digest: parsed.digest },
|
|
20281
|
+
comparedBy: comparable ? "digest" : "none",
|
|
20282
|
+
match: comparable ? parsed.digest === args.stampDigest : "unknown"
|
|
20283
|
+
};
|
|
20284
|
+
}
|
|
20285
|
+
if (parsed.tag) {
|
|
20286
|
+
const comparable = args.stampTag !== "unknown" && args.stampTag !== "";
|
|
20287
|
+
return {
|
|
20288
|
+
...base,
|
|
20289
|
+
live: { kind: "tag", tag: parsed.tag },
|
|
20290
|
+
comparedBy: comparable ? "tag" : "none",
|
|
20291
|
+
match: comparable ? parsed.tag === args.stampTag : "unknown"
|
|
20292
|
+
};
|
|
20293
|
+
}
|
|
20294
|
+
return { ...base, live: { kind: "unread" }, comparedBy: "none", match: "unknown" };
|
|
20295
|
+
}
|
|
20296
|
+
var LABEL = (s) => ` ${s}`.padEnd(22, " ");
|
|
20297
|
+
function renderLiveVerify(v, apiVersion, fmt2 = { ok: (s) => s, warn: (s) => s }) {
|
|
20298
|
+
const stamp = v.stampDigest ? `${v.stampTag} \xB7 ${v.stampDigest}` : v.stampTag;
|
|
20299
|
+
let live;
|
|
20300
|
+
switch (v.live.kind) {
|
|
20301
|
+
case "digest":
|
|
20302
|
+
live = v.live.digest;
|
|
20303
|
+
break;
|
|
20304
|
+
case "tag":
|
|
20305
|
+
live = `${v.live.tag} (tag-pinned \u2014 bytes not verified)`;
|
|
20306
|
+
break;
|
|
20307
|
+
default:
|
|
20308
|
+
live = "unknown";
|
|
20309
|
+
}
|
|
20310
|
+
const verdict = v.match === "unknown" ? fmt2.warn("unknown") : v.match ? fmt2.ok("yes") : fmt2.warn("no");
|
|
20311
|
+
const how = v.comparedBy === "none" ? "" : ` (compared by ${v.comparedBy})`;
|
|
20312
|
+
return [
|
|
20313
|
+
`${LABEL("stamp gateway:")}${stamp}`,
|
|
20314
|
+
`${LABEL("live gateway:")}${live}`,
|
|
20315
|
+
`${LABEL("match:")}${verdict}${how}`,
|
|
20316
|
+
`${LABEL("/api/version:")}${apiVersion}`
|
|
20317
|
+
];
|
|
20318
|
+
}
|
|
20319
|
+
|
|
20246
20320
|
// src/commands/platform/status.ts
|
|
20247
20321
|
var PlatformStatusCommand = class extends M8tCommand {
|
|
20248
20322
|
static paths = [["platform", "status"]];
|
|
@@ -20298,7 +20372,12 @@ var PlatformStatusCommand = class extends M8tCommand {
|
|
|
20298
20372
|
const rows = statusRows(manifest, stamp, tree);
|
|
20299
20373
|
let verify;
|
|
20300
20374
|
if (this.verify) {
|
|
20301
|
-
verify = await this.probeLive(
|
|
20375
|
+
verify = await this.probeLive(
|
|
20376
|
+
gw.containerAppResourceId,
|
|
20377
|
+
gw.gatewayUrl,
|
|
20378
|
+
stamp?.components.gateway.tag,
|
|
20379
|
+
stamp?.components.gateway.digest
|
|
20380
|
+
);
|
|
20302
20381
|
}
|
|
20303
20382
|
if (mode === "json") {
|
|
20304
20383
|
this.context.stdout.write(
|
|
@@ -20318,12 +20397,7 @@ var PlatformStatusCommand = class extends M8tCommand {
|
|
|
20318
20397
|
if (verify) {
|
|
20319
20398
|
log("");
|
|
20320
20399
|
log(colors.field("live verify:"));
|
|
20321
|
-
|
|
20322
|
-
log(` live gateway tag: ${verify.liveGatewayTag}`);
|
|
20323
|
-
log(
|
|
20324
|
-
` match: ${verify.gatewayTagMatch === "unknown" ? colors.warn("unknown") : verify.gatewayTagMatch ? colors.success("yes") : colors.warn("no")}`
|
|
20325
|
-
);
|
|
20326
|
-
log(` /api/version: ${verify.apiVersion}`);
|
|
20400
|
+
for (const line2 of renderLiveVerify(verify.gateway, verify.apiVersion, { ok: colors.success, warn: colors.warn })) log(line2);
|
|
20327
20401
|
}
|
|
20328
20402
|
return 0;
|
|
20329
20403
|
}
|
|
@@ -20347,11 +20421,11 @@ var PlatformStatusCommand = class extends M8tCommand {
|
|
|
20347
20421
|
* error, etc.) degrades the affected field to "unknown" rather than
|
|
20348
20422
|
* throwing — a verify probe must never crash the read-only status command.
|
|
20349
20423
|
*/
|
|
20350
|
-
async probeLive(gatewayResourceId, gatewayUrl, stampGatewayTag) {
|
|
20351
|
-
let
|
|
20424
|
+
async probeLive(gatewayResourceId, gatewayUrl, stampGatewayTag, stampGatewayDigest) {
|
|
20425
|
+
let liveImage;
|
|
20352
20426
|
try {
|
|
20353
20427
|
const { resourceGroup, name } = parseContainerAppResourceId(gatewayResourceId);
|
|
20354
|
-
|
|
20428
|
+
liveImage = (await runAz([
|
|
20355
20429
|
"containerapp",
|
|
20356
20430
|
"show",
|
|
20357
20431
|
"-g",
|
|
@@ -20362,11 +20436,9 @@ var PlatformStatusCommand = class extends M8tCommand {
|
|
|
20362
20436
|
"properties.template.containers[0].image",
|
|
20363
20437
|
"-o",
|
|
20364
20438
|
"tsv"
|
|
20365
|
-
])).trim();
|
|
20366
|
-
const tag = image.split(":").pop();
|
|
20367
|
-
if (tag) liveGatewayTag = tag;
|
|
20439
|
+
])).trim() || void 0;
|
|
20368
20440
|
} catch {
|
|
20369
|
-
|
|
20441
|
+
liveImage = void 0;
|
|
20370
20442
|
}
|
|
20371
20443
|
let apiVersion = "unknown";
|
|
20372
20444
|
try {
|
|
@@ -20380,9 +20452,17 @@ var PlatformStatusCommand = class extends M8tCommand {
|
|
|
20380
20452
|
} catch {
|
|
20381
20453
|
apiVersion = "unknown";
|
|
20382
20454
|
}
|
|
20383
|
-
|
|
20384
|
-
|
|
20385
|
-
|
|
20455
|
+
return {
|
|
20456
|
+
gateway: compareGatewayBinding({
|
|
20457
|
+
stampTag: stampGatewayTag ?? "unknown",
|
|
20458
|
+
// A stamp records "" for a component whose digest it never established, so
|
|
20459
|
+
// empty and absent are the SAME claim here. `??` would preserve "" and let a
|
|
20460
|
+
// caller treat it as a recorded value.
|
|
20461
|
+
stampDigest: stampGatewayDigest === "" ? void 0 : stampGatewayDigest,
|
|
20462
|
+
liveImage
|
|
20463
|
+
}),
|
|
20464
|
+
apiVersion
|
|
20465
|
+
};
|
|
20386
20466
|
}
|
|
20387
20467
|
};
|
|
20388
20468
|
|
|
@@ -20973,7 +21053,7 @@ async function buildConvergeDeps(args) {
|
|
|
20973
21053
|
...existing,
|
|
20974
21054
|
bicep: {
|
|
20975
21055
|
...existing.bicep,
|
|
20976
|
-
imageRef:
|
|
21056
|
+
imageRef: gatewayRefFromComponent(ctx.manifest.components.gateway)
|
|
20977
21057
|
},
|
|
20978
21058
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
20979
21059
|
}
|
|
@@ -28986,7 +29066,7 @@ ${colors.error("\u2717")} The GitHub App on disk is installed on ${colors.field(
|
|
|
28986
29066
|
// src/commands/bootstrap/launch.ts
|
|
28987
29067
|
var DEFAULT_RG = "rg-m8t-stack";
|
|
28988
29068
|
var DEFAULT_INSTALLER = "ghcr.io/m8t-labs/m8t-installer";
|
|
28989
|
-
var DEFAULT_INSTALLER_TAG = "v0.1.
|
|
29069
|
+
var DEFAULT_INSTALLER_TAG = "v0.1.55";
|
|
28990
29070
|
var ACI_NAME = "m8t-installer";
|
|
28991
29071
|
var MI_NAME = "m8t-installer-mi";
|
|
28992
29072
|
var BootstrapLaunchCommand = class extends M8tCommand {
|