@m8t-stack/cli 0.2.24 → 0.2.26

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 CHANGED
@@ -604,6 +604,22 @@ async function authedJsonResult(args) {
604
604
  async function authedJson(args) {
605
605
  return (await authedJsonResult(args)).data;
606
606
  }
607
+ async function authedJsonPagedValues(args) {
608
+ const maxPages = args.maxPages ?? 100;
609
+ const items = [];
610
+ let url = args.url;
611
+ for (let page = 0; url && page < maxPages; page++) {
612
+ const body = await authedJson({
613
+ credential: args.credential,
614
+ scope: args.scope,
615
+ method: "GET",
616
+ url
617
+ });
618
+ items.push(...body?.value ?? []);
619
+ url = body?.nextLink;
620
+ }
621
+ return items;
622
+ }
607
623
  var init_http = __esm({
608
624
  "src/lib/http.ts"() {
609
625
  "use strict";
@@ -1231,7 +1247,7 @@ var init_enable_hosted_brain = __esm({
1231
1247
  import { Builtins, Cli } from "clipanion";
1232
1248
 
1233
1249
  // src/lib/package-version.ts
1234
- var CLI_VERSION = "0.2.24";
1250
+ var CLI_VERSION = "0.2.26";
1235
1251
 
1236
1252
  // src/lib/render-error.ts
1237
1253
  init_errors();
@@ -13663,23 +13679,22 @@ var ACCOUNTS_API = "2024-10-01";
13663
13679
  var PROJECTS_API = "2025-04-01-preview";
13664
13680
  async function listProjectsForAccount(credential2, accountId) {
13665
13681
  const url = `${ARM}${accountId}/projects?api-version=${PROJECTS_API}`;
13666
- return await authedJson({ credential: credential2, scope: ARM_SCOPE2, method: "GET", url }) ?? {};
13682
+ return await authedJsonPagedValues({ credential: credential2, scope: ARM_SCOPE2, url });
13667
13683
  }
13668
13684
  function formatProjectCandidate(c) {
13669
13685
  return `${c.projectName} (account=${c.accountName}, ${c.region})`;
13670
13686
  }
13671
13687
  async function resolveFoundryProject(opts) {
13672
13688
  const candidates = [];
13673
- const accounts = await authedJson({
13689
+ const accounts = await authedJsonPagedValues({
13674
13690
  credential: opts.credential,
13675
13691
  scope: ARM_SCOPE2,
13676
- method: "GET",
13677
13692
  url: `${ARM}/subscriptions/${opts.subscriptionId}/providers/Microsoft.CognitiveServices/accounts?api-version=${ACCOUNTS_API}`
13678
- }) ?? {};
13679
- for (const acc of accounts.value ?? []) {
13693
+ });
13694
+ for (const acc of accounts) {
13680
13695
  if (acc.kind !== "AIServices" || !acc.name || !acc.id) continue;
13681
13696
  const projects = await listProjectsForAccount(opts.credential, acc.id);
13682
- for (const proj of projects.value ?? []) {
13697
+ for (const proj of projects) {
13683
13698
  if (!proj.name) continue;
13684
13699
  const projectName = proj.name.includes("/") ? proj.name.slice(proj.name.lastIndexOf("/") + 1) : proj.name;
13685
13700
  candidates.push({
@@ -20645,6 +20660,19 @@ async function ensureAppReg(opts) {
20645
20660
  await ensureExposeAnApi(created.appId, created.id);
20646
20661
  return { tenantId: opts.tenantId, clientId: created.appId, appObjectId: created.id };
20647
20662
  }
20663
+ async function ensureGatewayRedirectUri(gatewayClientId, fqdn) {
20664
+ const appObjectId = await azJson(
20665
+ ["ad", "app", "show", "--id", gatewayClientId, "--query", "id", "--output", "json"]
20666
+ );
20667
+ if (!appObjectId) {
20668
+ throw new LocalCliError({
20669
+ code: "APP_REG_OBJECT_ID_MISSING",
20670
+ message: `Could not resolve the object ID for app registration ${gatewayClientId}.`,
20671
+ hint: "You need directory read access to the app registration the gateway signs in against."
20672
+ });
20673
+ }
20674
+ await patchRedirectUris(appObjectId, fqdn);
20675
+ }
20648
20676
  async function patchRedirectUris(appObjectId, fqdn) {
20649
20677
  const targetUri = `https://${fqdn}`;
20650
20678
  const existing = await azJson(
@@ -24418,13 +24446,12 @@ var STORAGE_API2 = "2023-05-01";
24418
24446
  var LA_API = "2023-09-01";
24419
24447
  async function discoverLedgerResources(opts) {
24420
24448
  const { credential: credential2, subscriptionId, resourceGroup } = opts;
24421
- const storage = await authedJson({
24449
+ const storage = await authedJsonPagedValues({
24422
24450
  credential: credential2,
24423
24451
  scope: ARM_SCOPE8,
24424
- method: "GET",
24425
24452
  url: `${ARM4}/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.Storage/storageAccounts?api-version=${STORAGE_API2}`
24426
- }) ?? {};
24427
- const accounts = (storage.value ?? []).filter((a) => a.properties?.primaryEndpoints?.table);
24453
+ });
24454
+ const accounts = storage.filter((a) => a.properties?.primaryEndpoints?.table);
24428
24455
  const ledgerAcct = accounts.find((a) => (a.tags?.["m8t-stack:role"] ?? a.properties?.tags?.["m8t-stack:role"]) === "ledger") ?? (accounts.length === 1 ? accounts[0] : void 0);
24429
24456
  const ledgerTableEndpoint = ledgerAcct?.properties?.primaryEndpoints?.table?.replace(/\/$/, "");
24430
24457
  if (!ledgerTableEndpoint) {
@@ -24434,13 +24461,11 @@ async function discoverLedgerResources(opts) {
24434
24461
  hint: `Found: ${accounts.map((a) => a.name).join(", ") || "(none)"}. Tag the ledger account 'm8t-stack:role=ledger'.`
24435
24462
  });
24436
24463
  }
24437
- const laList = await authedJson({
24464
+ const ws = await authedJsonPagedValues({
24438
24465
  credential: credential2,
24439
24466
  scope: ARM_SCOPE8,
24440
- method: "GET",
24441
24467
  url: `${ARM4}/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.OperationalInsights/workspaces?api-version=${LA_API}`
24442
- }) ?? {};
24443
- const ws = laList.value ?? [];
24468
+ });
24444
24469
  const workspaceId = (ws.length === 1 ? ws[0] : ws.find((w) => w.properties?.customerId))?.properties?.customerId;
24445
24470
  if (!workspaceId) {
24446
24471
  throw new LocalCliError({
@@ -25653,7 +25678,7 @@ async function writeBootstrapState(state, home = os13.homedir()) {
25653
25678
  // src/commands/bootstrap/launch.ts
25654
25679
  var DEFAULT_RG = "rg-m8t-stack";
25655
25680
  var DEFAULT_INSTALLER = "ghcr.io/m8t-labs/m8t-installer";
25656
- var DEFAULT_INSTALLER_TAG = "v0.1.31";
25681
+ var DEFAULT_INSTALLER_TAG = "v0.1.32";
25657
25682
  var ACI_NAME = "m8t-installer";
25658
25683
  var MI_NAME = "m8t-installer-mi";
25659
25684
  var BootstrapLaunchCommand = class extends M8tCommand {
@@ -25664,8 +25689,8 @@ var BootstrapLaunchCommand = class extends M8tCommand {
25664
25689
  examples: [
25665
25690
  ["Launch in eastus2", "$0 bootstrap launch --location eastus2"],
25666
25691
  ["BYO app registration", "$0 bootstrap launch --location eastus2 --client-id <appId>"],
25667
- ["Pin a specific installer tag", "$0 bootstrap launch --location eastus2 --installer-tag v0.1.31"],
25668
- ["Override the full installer image ref", "$0 bootstrap launch --location eastus2 --installer-image ghcr.io/m8t-labs/m8t-installer:v0.1.31"]
25692
+ ["Pin a specific installer tag", "$0 bootstrap launch --location eastus2 --installer-tag v0.1.32"],
25693
+ ["Override the full installer image ref", "$0 bootstrap launch --location eastus2 --installer-image ghcr.io/m8t-labs/m8t-installer:v0.1.32"]
25669
25694
  ]
25670
25695
  });
25671
25696
  location = Option46.String("--location");
@@ -26461,6 +26486,20 @@ var BootstrapFinishCommand = class extends M8tCommand {
26461
26486
 
26462
26487
  `
26463
26488
  );
26489
+ try {
26490
+ await ensureGatewayRedirectUri(d.gatewayClientId, new URL(d.gatewayUrl).host);
26491
+ } catch (e) {
26492
+ const err = e;
26493
+ this.context.stderr.write(
26494
+ ` ${colors.error("\u26A0 could not authorize sign-in for your webapp:")} ${err.message}
26495
+ ${colors.hint(`Until this is fixed, opening ${d.gatewayUrl} will fail with AADSTS50011 (redirect URI mismatch).`)}
26496
+ ${colors.hint("Ask a directory admin to run:")}
26497
+ ${colors.hint(` m8t bootstrap finish --repo-root ${repoRoot} # (as an admin), or by hand:`)}
26498
+ ${colors.hint(` az ad app update --id ${d.gatewayClientId} --set spa.redirectUris="['${d.gatewayUrl}']" # (merge, do not overwrite)`)}
26499
+
26500
+ `
26501
+ );
26502
+ }
26464
26503
  } catch (e) {
26465
26504
  const err = e;
26466
26505
  this.context.stdout.write(`${colors.success("\u2705 The platform is live.")}