@continuous-excellence/ze-great-dashboard-aws 0.22.2 → 0.23.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/cli.js CHANGED
@@ -163,8 +163,23 @@ var azureDevOpsSourceSchema = z2.looseObject({
163
163
  project: z2.string().min(1),
164
164
  /** The branch whose build health the dashboard represents. */
165
165
  branch: z2.string().min(1).optional(),
166
- /** Azure DevOps Build API access is authenticated with a read-scoped PAT. */
167
- token_env: z2.string().min(1)
166
+ /** A PAT environment variable. The adapter sends it with Basic authentication. */
167
+ token_env: z2.string().min(1).optional(),
168
+ /** An environment variable naming a local, short-lived delegated-token file. */
169
+ entra_token_file_env: z2.string().min(1).optional()
170
+ }).superRefine((source, ctx) => {
171
+ if (source.token_env && source.entra_token_file_env) {
172
+ ctx.addIssue({
173
+ code: "custom",
174
+ message: "configure token_env or entra_token_file_env, not both"
175
+ });
176
+ }
177
+ if (!source.token_env && !source.entra_token_file_env) {
178
+ ctx.addIssue({
179
+ code: "custom",
180
+ message: "configure token_env or entra_token_file_env"
181
+ });
182
+ }
168
183
  });
169
184
  var sourceSchema = z2.looseObject({ type: z2.string().min(1), ...sourceAuthenticationSchema }).superRefine(exactlyOneGithubAuthenticationMode);
170
185
  var boardSchema = z2.object({
@@ -322,7 +337,7 @@ var pipelineActivitySchema = z4.object({
322
337
  });
323
338
  var pipelineStatusSchema = z4.object({
324
339
  type: z4.literal("pipeline-status"),
325
- status: z4.enum(["passed", "failed", "running", "cancelled", "unknown"]),
340
+ status: z4.enum(["passed", "failed", "warning", "running", "cancelled", "unknown"]),
326
341
  /** The source's unmodified status/result vocabulary, for an honest display. */
327
342
  rawStatus: z4.string(),
328
343
  name: z4.string().min(1),
package/dist/index.js CHANGED
@@ -844,8 +844,23 @@ var azureDevOpsSourceSchema = z2.looseObject({
844
844
  project: z2.string().min(1),
845
845
  /** The branch whose build health the dashboard represents. */
846
846
  branch: z2.string().min(1).optional(),
847
- /** Azure DevOps Build API access is authenticated with a read-scoped PAT. */
848
- token_env: z2.string().min(1)
847
+ /** A PAT environment variable. The adapter sends it with Basic authentication. */
848
+ token_env: z2.string().min(1).optional(),
849
+ /** An environment variable naming a local, short-lived delegated-token file. */
850
+ entra_token_file_env: z2.string().min(1).optional()
851
+ }).superRefine((source, ctx) => {
852
+ if (source.token_env && source.entra_token_file_env) {
853
+ ctx.addIssue({
854
+ code: "custom",
855
+ message: "configure token_env or entra_token_file_env, not both"
856
+ });
857
+ }
858
+ if (!source.token_env && !source.entra_token_file_env) {
859
+ ctx.addIssue({
860
+ code: "custom",
861
+ message: "configure token_env or entra_token_file_env"
862
+ });
863
+ }
849
864
  });
850
865
  var sourceSchema = z2.looseObject({ type: z2.string().min(1), ...sourceAuthenticationSchema }).superRefine(exactlyOneGithubAuthenticationMode);
851
866
  var boardSchema = z2.object({
@@ -1003,7 +1018,7 @@ var pipelineActivitySchema = z4.object({
1003
1018
  });
1004
1019
  var pipelineStatusSchema = z4.object({
1005
1020
  type: z4.literal("pipeline-status"),
1006
- status: z4.enum(["passed", "failed", "running", "cancelled", "unknown"]),
1021
+ status: z4.enum(["passed", "failed", "warning", "running", "cancelled", "unknown"]),
1007
1022
  /** The source's unmodified status/result vocabulary, for an honest display. */
1008
1023
  rawStatus: z4.string(),
1009
1024
  name: z4.string().min(1),
package/dist/lambda.mjs CHANGED
@@ -3851,7 +3851,7 @@ var init_getSSOTokenFilepath = __esm({
3851
3851
  });
3852
3852
 
3853
3853
  // node_modules/@smithy/core/dist-es/submodules/config/shared-ini-file-loader/getSSOTokenFromFile.js
3854
- import { readFile } from "node:fs/promises";
3854
+ import { readFile as readFile2 } from "node:fs/promises";
3855
3855
  var tokenIntercept, getSSOTokenFromFile;
3856
3856
  var init_getSSOTokenFromFile = __esm({
3857
3857
  "node_modules/@smithy/core/dist-es/submodules/config/shared-ini-file-loader/getSSOTokenFromFile.js"() {
@@ -3862,7 +3862,7 @@ var init_getSSOTokenFromFile = __esm({
3862
3862
  return tokenIntercept[id];
3863
3863
  }
3864
3864
  const ssoTokenFilepath = getSSOTokenFilepath(id);
3865
- const ssoTokenText = await readFile(ssoTokenFilepath, "utf8");
3865
+ const ssoTokenText = await readFile2(ssoTokenFilepath, "utf8");
3866
3866
  return JSON.parse(ssoTokenText);
3867
3867
  };
3868
3868
  }
@@ -3979,12 +3979,12 @@ var init_parseIni = __esm({
3979
3979
 
3980
3980
  // node_modules/@smithy/core/dist-es/submodules/config/shared-ini-file-loader/readFile.js
3981
3981
  import { readFile as fsReadFile } from "node:fs/promises";
3982
- var filePromises, fileIntercept, readFile2;
3982
+ var filePromises, fileIntercept, readFile3;
3983
3983
  var init_readFile = __esm({
3984
3984
  "node_modules/@smithy/core/dist-es/submodules/config/shared-ini-file-loader/readFile.js"() {
3985
3985
  filePromises = {};
3986
3986
  fileIntercept = {};
3987
- readFile2 = (path, options) => {
3987
+ readFile3 = (path, options) => {
3988
3988
  if (fileIntercept[path] !== void 0) {
3989
3989
  return fileIntercept[path];
3990
3990
  }
@@ -4022,10 +4022,10 @@ var init_loadSharedConfigFiles = __esm({
4022
4022
  resolvedConfigFilepath = join4(homeDir, configFilepath.slice(2));
4023
4023
  }
4024
4024
  const parsedFiles = await Promise.all([
4025
- readFile2(resolvedConfigFilepath, {
4025
+ readFile3(resolvedConfigFilepath, {
4026
4026
  ignoreCache: init.ignoreCache
4027
4027
  }).then(parseIni).then(getConfigData).catch(swallowError),
4028
- readFile2(resolvedFilepath, {
4028
+ readFile3(resolvedFilepath, {
4029
4029
  ignoreCache: init.ignoreCache
4030
4030
  }).then(parseIni).catch(swallowError)
4031
4031
  ]);
@@ -4056,7 +4056,7 @@ var init_loadSsoSessionData = __esm({
4056
4056
  init_parseIni();
4057
4057
  init_readFile();
4058
4058
  swallowError2 = () => ({});
4059
- loadSsoSessionData = async (init = {}) => readFile2(init.configFilepath ?? getConfigFilepath()).then(parseIni).then(getSsoSessionData).catch(swallowError2);
4059
+ loadSsoSessionData = async (init = {}) => readFile3(init.configFilepath ?? getConfigFilepath()).then(parseIni).then(getSsoSessionData).catch(swallowError2);
4060
4060
  }
4061
4061
  });
4062
4062
 
@@ -4701,7 +4701,7 @@ __export(config_exports, {
4701
4701
  nodeFipsConfigSelectors: () => nodeFipsConfigSelectors,
4702
4702
  numberSelector: () => numberSelector,
4703
4703
  parseKnownFiles: () => parseKnownFiles,
4704
- readFile: () => readFile2,
4704
+ readFile: () => readFile3,
4705
4705
  resolveCustomEndpointsConfig: () => resolveCustomEndpointsConfig,
4706
4706
  resolveDefaultsModeConfig: () => resolveDefaultsModeConfig,
4707
4707
  resolveEndpointsConfig: () => resolveEndpointsConfig,
@@ -64047,8 +64047,23 @@ var azureDevOpsSourceSchema = external_exports.looseObject({
64047
64047
  project: external_exports.string().min(1),
64048
64048
  /** The branch whose build health the dashboard represents. */
64049
64049
  branch: external_exports.string().min(1).optional(),
64050
- /** Azure DevOps Build API access is authenticated with a read-scoped PAT. */
64051
- token_env: external_exports.string().min(1)
64050
+ /** A PAT environment variable. The adapter sends it with Basic authentication. */
64051
+ token_env: external_exports.string().min(1).optional(),
64052
+ /** An environment variable naming a local, short-lived delegated-token file. */
64053
+ entra_token_file_env: external_exports.string().min(1).optional()
64054
+ }).superRefine((source, ctx) => {
64055
+ if (source.token_env && source.entra_token_file_env) {
64056
+ ctx.addIssue({
64057
+ code: "custom",
64058
+ message: "configure token_env or entra_token_file_env, not both"
64059
+ });
64060
+ }
64061
+ if (!source.token_env && !source.entra_token_file_env) {
64062
+ ctx.addIssue({
64063
+ code: "custom",
64064
+ message: "configure token_env or entra_token_file_env"
64065
+ });
64066
+ }
64052
64067
  });
64053
64068
  var sourceSchema = external_exports.looseObject({ type: external_exports.string().min(1), ...sourceAuthenticationSchema }).superRefine(exactlyOneGithubAuthenticationMode);
64054
64069
  function credentialEnvironmentNames(source) {
@@ -64217,7 +64232,7 @@ var pipelineActivitySchema = external_exports.object({
64217
64232
  });
64218
64233
  var pipelineStatusSchema = external_exports.object({
64219
64234
  type: external_exports.literal("pipeline-status"),
64220
- status: external_exports.enum(["passed", "failed", "running", "cancelled", "unknown"]),
64235
+ status: external_exports.enum(["passed", "failed", "warning", "running", "cancelled", "unknown"]),
64221
64236
  /** The source's unmodified status/result vocabulary, for an honest display. */
64222
64237
  rawStatus: external_exports.string(),
64223
64238
  name: external_exports.string().min(1),
@@ -64353,6 +64368,9 @@ function nearestLegalRectangle(desired, accepted) {
64353
64368
  return { x: candidate.x, y: candidate.y, w: candidate.w, h: candidate.h };
64354
64369
  }
64355
64370
 
64371
+ // packages/server/src/adapters/azure-devops.ts
64372
+ import { readFile } from "node:fs/promises";
64373
+
64356
64374
  // packages/server/src/upstream.ts
64357
64375
  function publicErrorMessage(kind) {
64358
64376
  switch (kind) {
@@ -64469,14 +64487,14 @@ function permittedAzureDevOpsCalls(panel, source) {
64469
64487
  async function fetchAzureDevOpsPipeline(args) {
64470
64488
  const panel = pipelinePanelSchema.parse(args.panel);
64471
64489
  const source = azureDevOpsSourceSchema.parse(args.source);
64472
- const token = args.credentials.get(source.token_env);
64473
- if (!token) {
64490
+ const authorization = await azureDevOpsAuthorization(source, args.credentials);
64491
+ if (!authorization) {
64474
64492
  return {
64475
64493
  response: errorResponse(
64476
64494
  errorEnvelope(
64477
64495
  panel.id,
64478
64496
  "unauthorized",
64479
- `Credential ${source.token_env} is not available.`,
64497
+ "Azure DevOps credentials are not available.",
64480
64498
  sourceLink(panel.pipeline, source)
64481
64499
  )
64482
64500
  ),
@@ -64485,7 +64503,7 @@ async function fetchAzureDevOpsPipeline(args) {
64485
64503
  }
64486
64504
  const call = buildsCall(panel.pipeline, source);
64487
64505
  copyValidators(args.requestHeaders, call.headers);
64488
- call.headers.set("authorization", `Basic ${btoa(`:${token}`)}`);
64506
+ call.headers.set("authorization", authorization);
64489
64507
  let upstream;
64490
64508
  try {
64491
64509
  upstream = await args.fetcher(call.url, { headers: call.headers });
@@ -64576,6 +64594,27 @@ async function fetchAzureDevOpsPipeline(args) {
64576
64594
  };
64577
64595
  }
64578
64596
  }
64597
+ var delegatedTokenFileSchema = external_exports.object({
64598
+ accessToken: external_exports.string().min(1),
64599
+ expiresAt: external_exports.string().min(1)
64600
+ });
64601
+ async function azureDevOpsAuthorization(source, credentials) {
64602
+ if (source.token_env) {
64603
+ const token = credentials.get(source.token_env);
64604
+ return token ? `Basic ${btoa(`:${token}`)}` : void 0;
64605
+ }
64606
+ if (!source.entra_token_file_env) return void 0;
64607
+ const tokenFile = credentials.get(source.entra_token_file_env);
64608
+ if (!tokenFile) return void 0;
64609
+ try {
64610
+ const token = delegatedTokenFileSchema.parse(JSON.parse(await readFile(tokenFile, "utf8")));
64611
+ const expiresAt = Date.parse(token.expiresAt);
64612
+ if (!Number.isFinite(expiresAt) || expiresAt <= Date.now()) return void 0;
64613
+ return `Bearer ${token.accessToken}`;
64614
+ } catch {
64615
+ return void 0;
64616
+ }
64617
+ }
64579
64618
  function buildsCall(definitionId, source) {
64580
64619
  const url2 = apiUrl(source, "build/builds");
64581
64620
  url2.searchParams.set("definitions", String(definitionId));
@@ -64626,6 +64665,7 @@ function normalizeStatus(status, result) {
64626
64665
  if (status !== "completed") return "unknown";
64627
64666
  if (result === "succeeded") return "passed";
64628
64667
  if (result === "failed") return "failed";
64668
+ if (result === "partiallySucceeded") return "warning";
64629
64669
  if (result === "canceled") return "cancelled";
64630
64670
  return "unknown";
64631
64671
  }
@@ -67916,10 +67956,10 @@ function safeDownloadFilename(value) {
67916
67956
  }
67917
67957
 
67918
67958
  // packages/server/src/board-config.ts
67919
- import { readFile as readFile3 } from "node:fs/promises";
67959
+ import { readFile as readFile4 } from "node:fs/promises";
67920
67960
  var import_yaml2 = __toESM(require_dist(), 1);
67921
67961
  async function loadBoardConfig(location, fetcher = globalThis.fetch, expectedSchemaUrl) {
67922
- const text = isUrl(location) ? await fetchBoardConfig(location, fetcher) : await readFile3(location, "utf-8");
67962
+ const text = isUrl(location) ? await fetchBoardConfig(location, fetcher) : await readFile4(location, "utf-8");
67923
67963
  const authoredSchemaUrl = readBoardSchemaModeline(text, expectedSchemaUrl);
67924
67964
  const result = boardConfigSchema.safeParse((0, import_yaml2.parse)(text));
67925
67965
  if (!result.success) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@continuous-excellence/ze-great-dashboard-aws",
3
- "version": "0.22.2",
3
+ "version": "0.23.0",
4
4
  "type": "module",
5
5
  "description": "AWS server runtime and CloudFormation deployment tooling for Ze Great Dashboard.",
6
6
  "keywords": [