@continuous-excellence/ze-great-dashboard-aws 0.27.8 → 0.27.10
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 +481 -149
- package/dist/index.js +459 -127
- package/dist/lambda.mjs +1560 -699
- package/package.json +2 -2
- package/dist/internal-board.d.ts +0 -61
package/dist/cli.js
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
// packages/aws/src/cli.ts
|
|
4
4
|
import { execFile as execFile2 } from "node:child_process";
|
|
5
|
-
import { readFile as
|
|
5
|
+
import { readFile as readFile7, writeFile as writeFile4 } from "node:fs/promises";
|
|
6
6
|
import { promisify as promisify2 } from "node:util";
|
|
7
|
-
import { parse as
|
|
7
|
+
import { parse as parse2 } from "yaml";
|
|
8
8
|
|
|
9
9
|
// packages/aws/src/doctor.ts
|
|
10
10
|
import { execFile } from "node:child_process";
|
|
11
|
-
import { readFile as
|
|
11
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
12
12
|
import { promisify } from "node:util";
|
|
13
|
-
import { parse
|
|
13
|
+
import { parse } from "yaml";
|
|
14
14
|
|
|
15
15
|
// packages/aws/src/bootstrap.ts
|
|
16
|
-
import { readFile as
|
|
16
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
17
17
|
import { fileURLToPath } from "node:url";
|
|
18
18
|
|
|
19
19
|
// packages/aws/src/compute-mode.ts
|
|
@@ -43,9 +43,15 @@ function computeMode(config) {
|
|
|
43
43
|
|
|
44
44
|
// packages/aws/src/release.ts
|
|
45
45
|
import { createHash } from "node:crypto";
|
|
46
|
-
import { mkdir,
|
|
46
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
47
47
|
import { join, resolve } from "node:path";
|
|
48
48
|
|
|
49
|
+
// packages/server/src/allowlist.ts
|
|
50
|
+
import { ZodError } from "zod";
|
|
51
|
+
|
|
52
|
+
// packages/server/src/adapters/azure-devops.ts
|
|
53
|
+
import { readFile } from "node:fs/promises";
|
|
54
|
+
|
|
49
55
|
// packages/shared/src/board-config.ts
|
|
50
56
|
import { z as z2 } from "zod";
|
|
51
57
|
|
|
@@ -68,7 +74,8 @@ function parseDuration(value2) {
|
|
|
68
74
|
return amount * UNIT_MILLIS[rawUnit];
|
|
69
75
|
}
|
|
70
76
|
var durationSchema = z.string().refine((value2) => parseDuration(value2) !== null, {
|
|
71
|
-
message: 'must be a positive duration like "30s", "5m", or "1h"'
|
|
77
|
+
message: 'must be a positive duration like "30s", "5m", or "1h"',
|
|
78
|
+
params: { constraint: 'Use a positive duration like "30s", "5m", or "1h".' }
|
|
72
79
|
}).brand();
|
|
73
80
|
|
|
74
81
|
// packages/shared/src/board-config.ts
|
|
@@ -154,7 +161,8 @@ var panelSchema = z2.looseObject({
|
|
|
154
161
|
ctx.addIssue({
|
|
155
162
|
code: "custom",
|
|
156
163
|
path: ["display"],
|
|
157
|
-
message: "display was removed; use density"
|
|
164
|
+
message: "display was removed; use density",
|
|
165
|
+
params: { constraint: "display was removed; use density" }
|
|
158
166
|
});
|
|
159
167
|
}
|
|
160
168
|
if (panel.type !== "http-value") return;
|
|
@@ -163,13 +171,15 @@ var panelSchema = z2.looseObject({
|
|
|
163
171
|
ctx.addIssue({
|
|
164
172
|
code: "custom",
|
|
165
173
|
path: ["url"],
|
|
166
|
-
message: "use facts URLs for grouped panels"
|
|
174
|
+
message: "use facts URLs for grouped panels",
|
|
175
|
+
params: { constraint: "use facts URLs for grouped panels" }
|
|
167
176
|
});
|
|
168
177
|
if (panel.json_path !== void 0)
|
|
169
178
|
ctx.addIssue({
|
|
170
179
|
code: "custom",
|
|
171
180
|
path: ["json_path"],
|
|
172
|
-
message: "use facts json_path values for grouped panels"
|
|
181
|
+
message: "use facts json_path values for grouped panels",
|
|
182
|
+
params: { constraint: "use facts json_path values for grouped panels" }
|
|
173
183
|
});
|
|
174
184
|
const seen = /* @__PURE__ */ new Map();
|
|
175
185
|
panel.facts.forEach((fact, index) => {
|
|
@@ -179,7 +189,8 @@ var panelSchema = z2.looseObject({
|
|
|
179
189
|
ctx.addIssue({
|
|
180
190
|
code: "custom",
|
|
181
191
|
path: ["facts", index, "id"],
|
|
182
|
-
message: `duplicate fact id "${fact.id}" (already used by fact at index ${first})
|
|
192
|
+
message: `duplicate fact id "${fact.id}" (already used by fact at index ${first})`,
|
|
193
|
+
params: { constraint: "Use a unique fact id within this panel." }
|
|
183
194
|
});
|
|
184
195
|
});
|
|
185
196
|
}
|
|
@@ -196,7 +207,11 @@ var sourceAuthenticationSchema = {
|
|
|
196
207
|
};
|
|
197
208
|
function exactlyOneGithubAuthenticationMode(source, ctx) {
|
|
198
209
|
if (source.token_env && source.github_app)
|
|
199
|
-
ctx.addIssue({
|
|
210
|
+
ctx.addIssue({
|
|
211
|
+
code: "custom",
|
|
212
|
+
message: "configure token_env or github_app, not both",
|
|
213
|
+
params: { constraint: "configure token_env or github_app, not both" }
|
|
214
|
+
});
|
|
200
215
|
}
|
|
201
216
|
var githubActionsSourceSchema = z2.looseObject({
|
|
202
217
|
type: z2.literal("github-actions"),
|
|
@@ -220,24 +235,44 @@ var azureDevOpsSourceSchema = z2.looseObject({
|
|
|
220
235
|
if (source.token_env && source.entra_token_file_env) {
|
|
221
236
|
ctx.addIssue({
|
|
222
237
|
code: "custom",
|
|
223
|
-
message: "configure token_env or entra_token_file_env, not both"
|
|
238
|
+
message: "configure token_env or entra_token_file_env, not both",
|
|
239
|
+
params: { constraint: "configure token_env or entra_token_file_env, not both" }
|
|
224
240
|
});
|
|
225
241
|
}
|
|
226
242
|
if (!source.token_env && !source.entra_token_file_env) {
|
|
227
243
|
ctx.addIssue({
|
|
228
244
|
code: "custom",
|
|
229
|
-
message: "configure token_env or entra_token_file_env"
|
|
245
|
+
message: "configure token_env or entra_token_file_env",
|
|
246
|
+
params: { constraint: "configure token_env or entra_token_file_env" }
|
|
230
247
|
});
|
|
231
248
|
}
|
|
232
249
|
});
|
|
233
250
|
var gitlabInstanceUrlSchema = z2.url().superRefine((value2, ctx) => {
|
|
234
251
|
const url = new URL(value2);
|
|
235
252
|
if (url.protocol !== "https:")
|
|
236
|
-
ctx.addIssue({
|
|
253
|
+
ctx.addIssue({
|
|
254
|
+
code: "custom",
|
|
255
|
+
message: "must be an HTTPS GitLab instance URL",
|
|
256
|
+
params: { constraint: "must be an HTTPS GitLab instance URL" }
|
|
257
|
+
});
|
|
237
258
|
if (url.username || url.password)
|
|
238
|
-
ctx.addIssue({
|
|
239
|
-
|
|
240
|
-
|
|
259
|
+
ctx.addIssue({
|
|
260
|
+
code: "custom",
|
|
261
|
+
message: "must not include credentials",
|
|
262
|
+
params: { constraint: "must not include credentials" }
|
|
263
|
+
});
|
|
264
|
+
if (url.search)
|
|
265
|
+
ctx.addIssue({
|
|
266
|
+
code: "custom",
|
|
267
|
+
message: "must not include a query string",
|
|
268
|
+
params: { constraint: "must not include a query string" }
|
|
269
|
+
});
|
|
270
|
+
if (url.hash)
|
|
271
|
+
ctx.addIssue({
|
|
272
|
+
code: "custom",
|
|
273
|
+
message: "must not include a fragment",
|
|
274
|
+
params: { constraint: "must not include a fragment" }
|
|
275
|
+
});
|
|
241
276
|
});
|
|
242
277
|
var gitlabCiSourceSchema = z2.looseObject({
|
|
243
278
|
type: z2.literal("gitlab-ci"),
|
|
@@ -251,6 +286,17 @@ var gitlabCiSourceSchema = z2.looseObject({
|
|
|
251
286
|
url: gitlabInstanceUrlSchema.optional().default("https://gitlab.com")
|
|
252
287
|
});
|
|
253
288
|
var sourceSchema = z2.looseObject({ type: z2.string().min(1), ...sourceAuthenticationSchema }).superRefine(exactlyOneGithubAuthenticationMode);
|
|
289
|
+
function credentialEnvironmentNames(source) {
|
|
290
|
+
const githubApp = githubAppSchema.safeParse(source.github_app);
|
|
291
|
+
return [
|
|
292
|
+
...source.token_env ? [source.token_env] : [],
|
|
293
|
+
...githubApp.success ? [
|
|
294
|
+
githubApp.data.app_id_env,
|
|
295
|
+
githubApp.data.private_key_env,
|
|
296
|
+
githubApp.data.installation_id_env
|
|
297
|
+
] : []
|
|
298
|
+
];
|
|
299
|
+
}
|
|
254
300
|
var boardSchema = z2.object({
|
|
255
301
|
refresh: durationSchema.optional(),
|
|
256
302
|
running_refresh: durationSchema.optional(),
|
|
@@ -267,7 +313,8 @@ var boardSchema = z2.object({
|
|
|
267
313
|
ctx.addIssue({
|
|
268
314
|
code: "custom",
|
|
269
315
|
path: [index, "id"],
|
|
270
|
-
message: `duplicate panel id "${panel.id}" (already used by panel at index ${firstIndex})
|
|
316
|
+
message: `duplicate panel id "${panel.id}" (already used by panel at index ${firstIndex})`,
|
|
317
|
+
params: { constraint: "Use a unique panel id within this board." }
|
|
271
318
|
});
|
|
272
319
|
});
|
|
273
320
|
})
|
|
@@ -287,15 +334,14 @@ var boardConfigSchema = z2.object({
|
|
|
287
334
|
auth: authSchema.optional()
|
|
288
335
|
}).superRefine((config, ctx) => {
|
|
289
336
|
for (const [sourceName, source] of Object.entries(config.sources)) {
|
|
290
|
-
const
|
|
291
|
-
if (!
|
|
292
|
-
const parsedSource =
|
|
337
|
+
const sourceSchema2 = source.type === "azure-devops" ? azureDevOpsSourceSchema : source.type === "gitlab-ci" ? gitlabCiSourceSchema : void 0;
|
|
338
|
+
if (!sourceSchema2) continue;
|
|
339
|
+
const parsedSource = sourceSchema2.safeParse(source);
|
|
293
340
|
if (!parsedSource.success) {
|
|
294
341
|
for (const issue of parsedSource.error.issues) {
|
|
295
342
|
ctx.addIssue({
|
|
296
|
-
|
|
297
|
-
path: ["sources", sourceName, ...issue.path]
|
|
298
|
-
message: issue.message
|
|
343
|
+
...issue,
|
|
344
|
+
path: ["sources", sourceName, ...issue.path]
|
|
299
345
|
});
|
|
300
346
|
}
|
|
301
347
|
}
|
|
@@ -308,7 +354,10 @@ var boardConfigSchema = z2.object({
|
|
|
308
354
|
ctx.addIssue({
|
|
309
355
|
code: "custom",
|
|
310
356
|
path: ["boards", boardName, "panels", panelIndex, "pipeline"],
|
|
311
|
-
message: "Azure DevOps pipeline-status panels require a positive numeric pipeline definition id"
|
|
357
|
+
message: "Azure DevOps pipeline-status panels require a positive numeric pipeline definition id",
|
|
358
|
+
params: {
|
|
359
|
+
constraint: "Provide a positive numeric Azure DevOps pipeline definition id."
|
|
360
|
+
}
|
|
312
361
|
});
|
|
313
362
|
}
|
|
314
363
|
});
|
|
@@ -471,95 +520,376 @@ var httpValueSchema = z4.object({
|
|
|
471
520
|
value: z4.union([z4.string(), z4.number(), z4.boolean()])
|
|
472
521
|
});
|
|
473
522
|
|
|
474
|
-
// packages/
|
|
475
|
-
import { parse, stringify } from "yaml";
|
|
476
|
-
import { z as z6 } from "zod";
|
|
477
|
-
|
|
478
|
-
// packages/aws/src/internal-board.ts
|
|
523
|
+
// packages/server/src/adapters/azure-devops.ts
|
|
479
524
|
import { z as z5 } from "zod";
|
|
480
|
-
var
|
|
481
|
-
var positionSchema2 = z5.union([
|
|
482
|
-
z5.object({
|
|
483
|
-
x: z5.number().int().min(0),
|
|
484
|
-
y: z5.number().int().min(0),
|
|
485
|
-
w: z5.number().int().min(1).max(12),
|
|
486
|
-
h: z5.number().int().min(1)
|
|
487
|
-
}),
|
|
488
|
-
z5.object({ x: z5.literal(0), y: z5.literal(0), w: z5.literal(0), h: z5.literal(0) })
|
|
489
|
-
]);
|
|
490
|
-
var panelSchema2 = z5.looseObject({
|
|
491
|
-
// Presentation-only; ids still address proxy calls and the generated allowlist.
|
|
492
|
-
label: z5.string().min(1).optional(),
|
|
525
|
+
var pipelinePanelSchema = z5.object({
|
|
493
526
|
id: z5.string().min(1),
|
|
494
|
-
type: z5.
|
|
495
|
-
source: z5.string().min(1)
|
|
496
|
-
|
|
497
|
-
position: positionSchema2.optional(),
|
|
498
|
-
refresh: durationSchema2.optional(),
|
|
499
|
-
link: z5.url().optional(),
|
|
500
|
-
url: z5.url().optional(),
|
|
501
|
-
json_path: z5.string().regex(/^\$(?:\.[A-Za-z_][A-Za-z0-9_]*|\[\d+\])*$/).optional()
|
|
502
|
-
}).superRefine((panel, ctx) => {
|
|
503
|
-
if ("display" in panel) {
|
|
504
|
-
ctx.addIssue({
|
|
505
|
-
code: "custom",
|
|
506
|
-
path: ["display"],
|
|
507
|
-
message: "display was removed; use density"
|
|
508
|
-
});
|
|
509
|
-
}
|
|
527
|
+
type: z5.literal("pipeline-status"),
|
|
528
|
+
source: z5.string().min(1),
|
|
529
|
+
pipeline: z5.number().int().positive()
|
|
510
530
|
});
|
|
511
|
-
var
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
if (source.token_env && source.github_app)
|
|
521
|
-
ctx.addIssue({ code: "custom", message: "configure token_env or github_app, not both" });
|
|
531
|
+
var buildSchema = z5.object({
|
|
532
|
+
id: z5.number().int().positive(),
|
|
533
|
+
buildNumber: z5.string().min(1),
|
|
534
|
+
status: z5.string().nullable().optional(),
|
|
535
|
+
result: z5.string().nullable().optional(),
|
|
536
|
+
sourceBranch: z5.string().min(1).nullable().optional(),
|
|
537
|
+
startTime: z5.string().nullable().optional(),
|
|
538
|
+
finishTime: z5.string().nullable().optional(),
|
|
539
|
+
lastChangedDate: z5.string().nullable().optional()
|
|
522
540
|
});
|
|
523
|
-
var
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
541
|
+
var buildsSchema = z5.object({ value: z5.array(buildSchema) });
|
|
542
|
+
var timelineSchema = z5.object({
|
|
543
|
+
records: z5.array(
|
|
544
|
+
z5.object({
|
|
545
|
+
id: z5.string().min(1),
|
|
546
|
+
parentId: z5.string().min(1).nullable().optional(),
|
|
547
|
+
type: z5.string().min(1),
|
|
548
|
+
name: z5.string().min(1),
|
|
549
|
+
state: z5.string().nullable().optional()
|
|
550
|
+
})
|
|
551
|
+
)
|
|
552
|
+
});
|
|
553
|
+
function permittedAzureDevOpsCalls(panel, source) {
|
|
554
|
+
const { panel: parsedPanel, source: parsedSource } = z5.object({ panel: pipelinePanelSchema, source: azureDevOpsSourceSchema }).parse({ panel, source });
|
|
555
|
+
return [buildsCall(parsedPanel.pipeline, parsedSource)];
|
|
556
|
+
}
|
|
557
|
+
var delegatedTokenFileSchema = z5.object({
|
|
558
|
+
accessToken: z5.string().min(1),
|
|
559
|
+
expiresAt: z5.string().min(1)
|
|
560
|
+
});
|
|
561
|
+
function buildsCall(definitionId, source) {
|
|
562
|
+
const url = apiUrl(source, "build/builds");
|
|
563
|
+
url.searchParams.set("definitions", String(definitionId));
|
|
564
|
+
if (source.branch) url.searchParams.set("branchName", adoBranch(source.branch));
|
|
565
|
+
url.searchParams.set("queryOrder", "queueTimeDescending");
|
|
566
|
+
url.searchParams.set("$top", "1");
|
|
567
|
+
return { url: url.toString(), headers: new Headers({ accept: "application/json" }) };
|
|
568
|
+
}
|
|
569
|
+
function apiUrl(source, suffix) {
|
|
570
|
+
const url = new URL(
|
|
571
|
+
`https://dev.azure.com/${encodeURIComponent(source.organization)}/${encodeURIComponent(source.project)}/_apis/${suffix}`
|
|
572
|
+
);
|
|
573
|
+
url.searchParams.set("api-version", "7.1");
|
|
574
|
+
return url;
|
|
575
|
+
}
|
|
576
|
+
function adoBranch(branch) {
|
|
577
|
+
return branch.startsWith("refs/") ? branch : `refs/heads/${branch}`;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// packages/server/src/adapters/github-actions.ts
|
|
581
|
+
import { z as z6 } from "zod";
|
|
582
|
+
var pipelinePanelSchema2 = z6.object({
|
|
583
|
+
id: z6.string().min(1),
|
|
584
|
+
type: z6.literal("pipeline-status"),
|
|
585
|
+
source: z6.string().min(1),
|
|
586
|
+
/** GitHub accepts a workflow filename or numeric workflow id in this URL segment. */
|
|
587
|
+
pipeline: z6.string().min(1)
|
|
588
|
+
});
|
|
589
|
+
var pullRequestHealthPanelSchema = z6.object({
|
|
590
|
+
id: z6.string().min(1),
|
|
591
|
+
type: z6.literal("pull-request-health"),
|
|
592
|
+
source: z6.string().min(1),
|
|
593
|
+
base_branch: z6.string().min(1),
|
|
594
|
+
update_workflows: z6.array(
|
|
595
|
+
z6.object({
|
|
596
|
+
workflow: z6.string().min(1),
|
|
597
|
+
branch_prefixes: z6.array(z6.string().min(1)).min(1)
|
|
598
|
+
})
|
|
599
|
+
).min(1),
|
|
600
|
+
build_workflow: z6.string().min(1)
|
|
601
|
+
});
|
|
602
|
+
var runSchema = z6.object({
|
|
603
|
+
id: z6.number().int().positive().optional(),
|
|
604
|
+
status: z6.string(),
|
|
605
|
+
conclusion: z6.string().nullable(),
|
|
606
|
+
name: z6.string().min(1),
|
|
607
|
+
html_url: z6.url(),
|
|
608
|
+
/** The branch that produced this run; absent for some event types. */
|
|
609
|
+
head_branch: z6.string().min(1).nullable().optional(),
|
|
610
|
+
// Timestamp quality should only remove timing advice, never make an otherwise useful run unreadable.
|
|
611
|
+
run_started_at: z6.string().nullable().optional(),
|
|
612
|
+
updated_at: z6.string().optional()
|
|
613
|
+
});
|
|
614
|
+
var runsSchema = z6.object({ workflow_runs: z6.array(runSchema) });
|
|
615
|
+
var jobsSchema = z6.object({
|
|
616
|
+
jobs: z6.array(
|
|
617
|
+
z6.object({
|
|
618
|
+
name: z6.string().min(1),
|
|
619
|
+
status: z6.string(),
|
|
620
|
+
steps: z6.array(z6.object({ name: z6.string().min(1), status: z6.string() })).optional()
|
|
621
|
+
})
|
|
622
|
+
)
|
|
623
|
+
});
|
|
624
|
+
var pullRequestsSchema = z6.array(
|
|
625
|
+
z6.object({
|
|
626
|
+
number: z6.number().int().positive(),
|
|
627
|
+
html_url: z6.url(),
|
|
628
|
+
head: z6.object({ ref: z6.string().min(1) }),
|
|
629
|
+
base: z6.object({ ref: z6.string().min(1) })
|
|
537
630
|
})
|
|
631
|
+
);
|
|
632
|
+
function permittedGithubActionsCalls(panel, source, _credentials) {
|
|
633
|
+
const { panel: parsedPanel, source: parsedSource } = z6.object({ panel: pipelinePanelSchema2, source: githubActionsSourceSchema }).parse({ panel, source });
|
|
634
|
+
const url = new URL(
|
|
635
|
+
`https://api.github.com/repos/${parsedSource.repo}/actions/workflows/${encodeURIComponent(parsedPanel.pipeline)}/runs`
|
|
636
|
+
);
|
|
637
|
+
if (parsedSource.branch) url.searchParams.set("branch", parsedSource.branch);
|
|
638
|
+
url.searchParams.set("per_page", "1");
|
|
639
|
+
return [{ url: url.toString(), headers: new Headers() }];
|
|
640
|
+
}
|
|
641
|
+
function pullRequestHealthCapabilities(panel) {
|
|
642
|
+
const { panel: parsed } = z6.object({ panel: pullRequestHealthPanelSchema }).parse({ panel });
|
|
643
|
+
return {
|
|
644
|
+
panel: parsed,
|
|
645
|
+
configuredUpdateWorkflow(workflow) {
|
|
646
|
+
return parsed.update_workflows.find((candidate) => candidate.workflow === workflow);
|
|
647
|
+
},
|
|
648
|
+
permitsBuildBranch(branch) {
|
|
649
|
+
return parsed.update_workflows.some(
|
|
650
|
+
({ branch_prefixes }) => branch_prefixes.some((prefix) => branch.startsWith(prefix))
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// packages/server/src/adapters/gitlab-ci.ts
|
|
657
|
+
import { z as z7 } from "zod";
|
|
658
|
+
var pipelinePanelSchema3 = z7.object({
|
|
659
|
+
id: z7.string().min(1),
|
|
660
|
+
type: z7.literal("pipeline-status"),
|
|
661
|
+
source: z7.string().min(1)
|
|
538
662
|
});
|
|
539
|
-
var
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
subjects: z5.array(z5.string().min(1)).optional()
|
|
548
|
-
}).optional()
|
|
549
|
-
}).optional()
|
|
663
|
+
var pipelineSchema = z7.object({
|
|
664
|
+
id: z7.number().int().positive(),
|
|
665
|
+
name: z7.string().min(1).nullable().optional(),
|
|
666
|
+
status: z7.string(),
|
|
667
|
+
ref: z7.string().min(1).nullable().optional(),
|
|
668
|
+
created_at: z7.string().nullable().optional(),
|
|
669
|
+
updated_at: z7.string().nullable().optional(),
|
|
670
|
+
web_url: z7.url()
|
|
550
671
|
});
|
|
551
|
-
function
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
672
|
+
function permittedGitlabCiCalls(panel, source) {
|
|
673
|
+
const { source: parsedSource } = z7.object({ panel: pipelinePanelSchema3, source: gitlabCiSourceSchema }).parse({ panel, source });
|
|
674
|
+
return [pipelinesCall(parsedSource)];
|
|
675
|
+
}
|
|
676
|
+
function pipelinesCall(source) {
|
|
677
|
+
const url = new URL(source.url);
|
|
678
|
+
url.pathname = `${url.pathname.replace(/\/$/, "")}/api/v4/projects/${encodeURIComponent(source.project)}/pipelines`;
|
|
679
|
+
url.searchParams.set("per_page", "1");
|
|
680
|
+
if (source.branch) url.searchParams.set("ref", source.branch);
|
|
681
|
+
return { url: url.toString(), headers: new Headers({ accept: "application/json" }) };
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// packages/server/src/adapters/http-value.ts
|
|
685
|
+
import { z as z8 } from "zod";
|
|
686
|
+
function permittedHttpValueCalls(panel) {
|
|
687
|
+
const grouped = httpValueGroupedPanelSchema.safeParse(panel);
|
|
688
|
+
const urls = grouped.success ? grouped.data.facts.map((fact) => fact.url) : [z8.object({ panel: httpValueScalarPanelSchema }).parse({ panel }).panel.url];
|
|
689
|
+
return urls.map(permittedCall);
|
|
690
|
+
}
|
|
691
|
+
function permittedCall(value2) {
|
|
692
|
+
const url = new URL(value2);
|
|
693
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
694
|
+
throw new Error("http-value URLs must use http or https");
|
|
695
|
+
return { url: url.toString(), headers: new Headers({ accept: "application/json, text/plain" }) };
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// packages/server/src/configuration-error.ts
|
|
699
|
+
var ConfigurationError = class extends Error {
|
|
700
|
+
constructor(message2, diagnostics) {
|
|
701
|
+
super(message2);
|
|
702
|
+
this.diagnostics = diagnostics;
|
|
703
|
+
}
|
|
704
|
+
diagnostics;
|
|
705
|
+
};
|
|
706
|
+
function configurationLocation(path) {
|
|
707
|
+
return path.reduce(
|
|
708
|
+
(location, part) => typeof part === "number" ? `${location}[${part}]` : `${location}${location ? "." : ""}${String(part)}`,
|
|
709
|
+
""
|
|
710
|
+
) || "configuration";
|
|
711
|
+
}
|
|
712
|
+
function boardConfigurationLocation(config, path) {
|
|
713
|
+
const [record, key, ...rest] = path;
|
|
714
|
+
if ((record === "boards" || record === "sources") && key !== void 0) {
|
|
715
|
+
const entries = config && typeof config === "object" ? Reflect.get(config, record) : void 0;
|
|
716
|
+
const index = entries && typeof entries === "object" ? Object.keys(entries).indexOf(String(key)) : -1;
|
|
717
|
+
return configurationLocation([record, index, ...rest]);
|
|
718
|
+
}
|
|
719
|
+
return configurationLocation(path);
|
|
720
|
+
}
|
|
721
|
+
function schemaDiagnostics(error, locate, kind = "schema") {
|
|
722
|
+
return error.issues.map((issue) => ({
|
|
723
|
+
kind,
|
|
724
|
+
location: locate(issue.path),
|
|
725
|
+
constraint: correctiveConstraint(issue)
|
|
726
|
+
}));
|
|
727
|
+
}
|
|
728
|
+
function correctiveConstraint(issue) {
|
|
729
|
+
switch (issue.code) {
|
|
730
|
+
case "invalid_type":
|
|
731
|
+
return `Provide a value of type ${issue.expected}.`;
|
|
732
|
+
case "too_big":
|
|
733
|
+
return `Use ${issue.inclusive ? "at most" : "fewer than"} ${issue.maximum} ${issue.origin === "array" ? "entries" : issue.origin === "string" ? "characters" : "as the value"}.`;
|
|
734
|
+
case "too_small":
|
|
735
|
+
return `Use ${issue.inclusive ? "at least" : "more than"} ${issue.minimum} ${issue.origin === "array" ? "entries" : issue.origin === "string" ? "characters" : "as the value"}.`;
|
|
736
|
+
// Format messages are fixed by our schemas (or Zod); unlike custom issues they contain no authored values.
|
|
737
|
+
case "invalid_format":
|
|
738
|
+
return issue.message;
|
|
739
|
+
case "invalid_value":
|
|
740
|
+
return "Use one of the values allowed by the board schema.";
|
|
741
|
+
case "custom":
|
|
742
|
+
return typeof issue.params?.constraint === "string" ? issue.params.constraint : "Correct this field according to the board schema.";
|
|
743
|
+
default:
|
|
744
|
+
return "Provide a value matching the board schema for this field.";
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// packages/server/src/allowlist.ts
|
|
749
|
+
function deriveValidatedAllowlist(config) {
|
|
750
|
+
return derive(config, true);
|
|
751
|
+
}
|
|
752
|
+
function derive(config, rejectUnsupported) {
|
|
753
|
+
const allowed = /* @__PURE__ */ new Map();
|
|
754
|
+
for (const [boardName, board] of Object.entries(config.boards)) {
|
|
755
|
+
for (const panel of board.panels) {
|
|
756
|
+
const source = panel.source ? config.sources[panel.source] : void 0;
|
|
757
|
+
try {
|
|
758
|
+
const capability = panelCapability(panel, source);
|
|
759
|
+
if (capability.kind === "unsupported") {
|
|
760
|
+
if (rejectUnsupported) throw new Error("no bounded operations");
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
if (capability.kind === "server")
|
|
764
|
+
allowed.set(`${boardName}/${panel.id}`, new Set(capability.operations));
|
|
765
|
+
} catch (error) {
|
|
766
|
+
if (rejectUnsupported) {
|
|
767
|
+
const location = `boards[${Object.keys(config.boards).indexOf(boardName)}].panels[${board.panels.indexOf(panel)}]`;
|
|
768
|
+
throw new ConfigurationError(
|
|
769
|
+
unsupportedPanelOperation(boardName, panel, source, error).message,
|
|
770
|
+
error instanceof ZodError ? schemaDiagnostics(
|
|
771
|
+
error,
|
|
772
|
+
([subject, ...path]) => {
|
|
773
|
+
const root = subject === "source" ? ["sources", Object.keys(config.sources).indexOf(panel.source ?? "")] : [
|
|
774
|
+
"boards",
|
|
775
|
+
Object.keys(config.boards).indexOf(boardName),
|
|
776
|
+
"panels",
|
|
777
|
+
board.panels.indexOf(panel)
|
|
778
|
+
];
|
|
779
|
+
return configurationLocation([...root, ...path]);
|
|
780
|
+
},
|
|
781
|
+
"panel-admission"
|
|
782
|
+
) : [
|
|
783
|
+
{
|
|
784
|
+
kind: "panel-admission",
|
|
785
|
+
location,
|
|
786
|
+
constraint: "Use a supported panel/source combination with bounded HTTP(S) operations."
|
|
787
|
+
}
|
|
788
|
+
]
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
throw error;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
return allowed;
|
|
796
|
+
}
|
|
797
|
+
function panelCapability(panel, source) {
|
|
798
|
+
if (panel.type === "pipeline-status" && source?.type === "github-actions") {
|
|
799
|
+
permittedGithubActionsCalls(panel, source);
|
|
800
|
+
return { kind: "server", operations: ["read"] };
|
|
801
|
+
}
|
|
802
|
+
if (panel.type === "pipeline-status" && source?.type === "azure-devops") {
|
|
803
|
+
permittedAzureDevOpsCalls(panel, source);
|
|
804
|
+
return { kind: "server", operations: ["read"] };
|
|
805
|
+
}
|
|
806
|
+
if (panel.type === "pipeline-status" && source?.type === "gitlab-ci") {
|
|
807
|
+
permittedGitlabCiCalls(panel, source);
|
|
808
|
+
return { kind: "server", operations: ["read"] };
|
|
809
|
+
}
|
|
810
|
+
if (panel.type === "http-value") {
|
|
811
|
+
permittedHttpValueCalls(panel);
|
|
812
|
+
return { kind: "server", operations: ["read"] };
|
|
813
|
+
}
|
|
814
|
+
if (panel.type === "pull-request-health" && source?.type === "github-actions") {
|
|
815
|
+
pullRequestHealthCapabilities(panel);
|
|
816
|
+
return {
|
|
817
|
+
kind: "server",
|
|
818
|
+
operations: ["pull-requests", "update-workflow", "pull-request-build"]
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
if (panel.type === "pipeline-animation-demo") return { kind: "client-only" };
|
|
822
|
+
return { kind: "unsupported" };
|
|
823
|
+
}
|
|
824
|
+
function unsupportedPanelOperation(boardName, panel, source, error) {
|
|
825
|
+
const sourceName = panel.source ?? "(none)";
|
|
826
|
+
const sourceType = source?.type ?? "(none)";
|
|
827
|
+
const detail = error instanceof Error && error.message !== "no bounded operations" ? ` ${error.message}` : "";
|
|
828
|
+
return new Error(
|
|
829
|
+
`Unsupported configured panel operation: board "${boardName}", panel "${panel.id}", source "${sourceName}" (${sourceType}), signal "${panel.type}".${detail} Configure a supported panel/source combination and all adapter-required fields.`
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// packages/server/src/board-config.ts
|
|
834
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
835
|
+
import { parse as parseYaml, YAMLParseError } from "yaml";
|
|
836
|
+
async function loadBoardConfig(location, fetcher = globalThis.fetch, expectedSchemaUrl) {
|
|
837
|
+
const text = isUrl(location) ? await fetchBoardConfig(location, fetcher) : await readFile2(location, "utf-8");
|
|
838
|
+
let authoredSchemaUrl;
|
|
839
|
+
try {
|
|
840
|
+
authoredSchemaUrl = readBoardSchemaModeline(text, expectedSchemaUrl);
|
|
841
|
+
} catch (error) {
|
|
842
|
+
throw new ConfigurationError(error instanceof Error ? error.message : "Invalid modeline", [
|
|
843
|
+
{
|
|
844
|
+
kind: "modeline",
|
|
845
|
+
location: "line 1",
|
|
846
|
+
constraint: "Add a first-line yaml-language-server schema modeline ending in /board-config.schema.json."
|
|
847
|
+
}
|
|
848
|
+
]);
|
|
849
|
+
}
|
|
850
|
+
let parsed;
|
|
851
|
+
try {
|
|
852
|
+
parsed = parseYaml(text);
|
|
853
|
+
} catch (error) {
|
|
854
|
+
const position = error instanceof YAMLParseError ? error.linePos?.[0] : void 0;
|
|
855
|
+
const location2 = position ? `line ${position.line}, column ${position.col}` : "configuration";
|
|
856
|
+
throw new ConfigurationError(
|
|
857
|
+
`Invalid board configuration YAML at ${location2}: correct YAML syntax.`,
|
|
858
|
+
[
|
|
859
|
+
{
|
|
860
|
+
kind: "yaml",
|
|
861
|
+
location: location2,
|
|
862
|
+
constraint: "Correct YAML syntax and indentation."
|
|
863
|
+
}
|
|
864
|
+
]
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
const result = boardConfigSchema.safeParse(parsed);
|
|
868
|
+
if (!result.success) {
|
|
869
|
+
const stale = expectedSchemaUrl && authoredSchemaUrl !== expectedSchemaUrl ? `
|
|
870
|
+
Stale schema modeline: expected ${expectedSchemaUrl}` : "";
|
|
871
|
+
throw new ConfigurationError(
|
|
872
|
+
`Invalid board configuration:
|
|
873
|
+
${result.error.message}${stale}`,
|
|
874
|
+
schemaDiagnostics(result.error, (path) => boardConfigurationLocation(parsed, path))
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
return result.data;
|
|
878
|
+
}
|
|
879
|
+
function isUrl(value2) {
|
|
880
|
+
return /^https?:\/\//i.test(value2);
|
|
881
|
+
}
|
|
882
|
+
async function fetchBoardConfig(url, fetcher) {
|
|
883
|
+
const response = await fetcher(url);
|
|
884
|
+
if (!response.ok)
|
|
885
|
+
throw new Error(
|
|
886
|
+
`Unable to fetch board configuration from ${url}: ${response.status} ${response.statusText}`
|
|
887
|
+
);
|
|
888
|
+
return response.text();
|
|
560
889
|
}
|
|
561
890
|
|
|
562
891
|
// packages/aws/src/release.ts
|
|
892
|
+
import { stringify } from "yaml";
|
|
563
893
|
var CORE_RUNTIME_VERSION = "1.0.0";
|
|
564
894
|
var CANONICAL_ASSET_DOMAIN = "https://public-assets.zegreatrob.com";
|
|
565
895
|
function legacyAssetPath(version, domain = CANONICAL_ASSET_DOMAIN) {
|
|
@@ -582,22 +912,27 @@ function normalizeAssetPath(value2) {
|
|
|
582
912
|
return assetPath;
|
|
583
913
|
}
|
|
584
914
|
async function validateBoardConfig(path, expectedSchemaUrl) {
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
915
|
+
const config = await loadBoardConfig(resolve(path), void 0, expectedSchemaUrl).catch(
|
|
916
|
+
(error) => {
|
|
917
|
+
throw new Error(
|
|
918
|
+
`${path}: ${error instanceof Error ? error.message : "Invalid board configuration"}`
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
);
|
|
922
|
+
try {
|
|
923
|
+
deriveValidatedAllowlist(config);
|
|
924
|
+
} catch (error) {
|
|
925
|
+
throw new Error(
|
|
926
|
+
`${path}: ${error instanceof Error ? error.message : "Invalid panel configuration"}`
|
|
927
|
+
);
|
|
593
928
|
}
|
|
594
929
|
const yaml = `${boardSchemaModeline(expectedSchemaUrl)}
|
|
595
|
-
${stringify(
|
|
930
|
+
${stringify(config, { sortMapEntries: true })}`;
|
|
596
931
|
return {
|
|
597
932
|
yaml,
|
|
598
933
|
sha256: sha256(yaml),
|
|
599
|
-
usesCredentials: Object.values(
|
|
600
|
-
(
|
|
934
|
+
usesCredentials: Object.values(config.sources).some(
|
|
935
|
+
(source) => credentialEnvironmentNames(source).length > 0
|
|
601
936
|
)
|
|
602
937
|
};
|
|
603
938
|
}
|
|
@@ -750,11 +1085,11 @@ async function bootstrapTemplatePath(kind, mode = "lambda") {
|
|
|
750
1085
|
return fileURLToPath(new URL(templates[kind][mode], import.meta.url));
|
|
751
1086
|
}
|
|
752
1087
|
async function bootstrapTemplate(kind, mode = "lambda") {
|
|
753
|
-
return
|
|
1088
|
+
return readFile3(await bootstrapTemplatePath(kind, mode), "utf8");
|
|
754
1089
|
}
|
|
755
1090
|
async function installedBootstrapDesiredState(config = {}) {
|
|
756
1091
|
const packageManifest = JSON.parse(
|
|
757
|
-
await
|
|
1092
|
+
await readFile3(new URL("../package.json", import.meta.url), "utf8")
|
|
758
1093
|
);
|
|
759
1094
|
return desiredStateFromTemplates(
|
|
760
1095
|
packageVersion(packageManifest),
|
|
@@ -824,7 +1159,7 @@ function inspectTemplate(kind, path, template) {
|
|
|
824
1159
|
}
|
|
825
1160
|
async function bootstrapPlan(config) {
|
|
826
1161
|
const packageManifest = JSON.parse(
|
|
827
|
-
await
|
|
1162
|
+
await readFile3(new URL("../package.json", import.meta.url), "utf8")
|
|
828
1163
|
);
|
|
829
1164
|
const packageTemplates = await installedTemplateInspections(computeMode(config));
|
|
830
1165
|
const installedDesiredState = desiredStateFromTemplates(
|
|
@@ -997,7 +1332,7 @@ function requiredBootstrapParameters(kind, values) {
|
|
|
997
1332
|
}
|
|
998
1333
|
|
|
999
1334
|
// packages/aws/src/index.ts
|
|
1000
|
-
import { cp,
|
|
1335
|
+
import { cp, readFile as readFile5, rm, writeFile as writeFile3 } from "node:fs/promises";
|
|
1001
1336
|
import { join as join2, resolve as resolve2 } from "node:path";
|
|
1002
1337
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1003
1338
|
|
|
@@ -2039,7 +2374,7 @@ async function checkBootstrap(config, options, dependencies) {
|
|
|
2039
2374
|
}
|
|
2040
2375
|
|
|
2041
2376
|
// packages/aws/src/guided.ts
|
|
2042
|
-
import { readFile as
|
|
2377
|
+
import { readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
|
|
2043
2378
|
|
|
2044
2379
|
// packages/aws/src/handoff.ts
|
|
2045
2380
|
var githubSubjectKeys = [
|
|
@@ -2555,7 +2890,7 @@ async function scaffoldBootstrapManifest(input) {
|
|
|
2555
2890
|
async function upgradeBootstrapManifest(path) {
|
|
2556
2891
|
let parsed;
|
|
2557
2892
|
try {
|
|
2558
|
-
parsed = JSON.parse(await
|
|
2893
|
+
parsed = JSON.parse(await readFile4(path, "utf8"));
|
|
2559
2894
|
} catch (error) {
|
|
2560
2895
|
throw new Error(
|
|
2561
2896
|
`Unable to read bootstrap manifest ${path}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -2851,11 +3186,8 @@ function deploymentTemplate(template, values) {
|
|
|
2851
3186
|
}
|
|
2852
3187
|
async function packageLambda(options) {
|
|
2853
3188
|
const outputDir = resolve2(options.outputDir);
|
|
2854
|
-
await mkdir2(outputDir, { recursive: true });
|
|
2855
3189
|
const runtimeDir = join2(outputDir, "lambda");
|
|
2856
|
-
await mkdir2(runtimeDir, { recursive: true });
|
|
2857
3190
|
const lambdaSource = fileURLToPath2(new URL("../dist/lambda.mjs", import.meta.url));
|
|
2858
|
-
await cp(lambdaSource, join2(runtimeDir, "index.mjs"));
|
|
2859
3191
|
const release = await assembleRelease({
|
|
2860
3192
|
boardConfigPath: options.boardConfigPath,
|
|
2861
3193
|
outputDir: runtimeDir,
|
|
@@ -2865,12 +3197,13 @@ async function packageLambda(options) {
|
|
|
2865
3197
|
assetDomain: options.assetDomain,
|
|
2866
3198
|
secretReference: options.secretReference
|
|
2867
3199
|
});
|
|
3200
|
+
await cp(lambdaSource, join2(runtimeDir, "index.mjs"));
|
|
2868
3201
|
const runtimeMetadata = {
|
|
2869
3202
|
...release.metadata,
|
|
2870
3203
|
computeMode: "lambda",
|
|
2871
3204
|
artifactChecksums: {
|
|
2872
3205
|
...release.metadata.artifactChecksums,
|
|
2873
|
-
"index.mjs": sha256(await
|
|
3206
|
+
"index.mjs": sha256(await readFile5(join2(runtimeDir, "index.mjs")))
|
|
2874
3207
|
}
|
|
2875
3208
|
};
|
|
2876
3209
|
await writeFile3(join2(runtimeDir, "release.json"), `${JSON.stringify(runtimeMetadata, null, 2)}
|
|
@@ -2885,7 +3218,7 @@ async function packageLambda(options) {
|
|
|
2885
3218
|
archiveFiles.map(async (name) => [
|
|
2886
3219
|
name,
|
|
2887
3220
|
[
|
|
2888
|
-
strToU8(await
|
|
3221
|
+
strToU8(await readFile5(join2(runtimeDir, name), "utf8")),
|
|
2889
3222
|
{ mtime: new Date(1980, 0, 1, 0, 0, 0), level: 9 }
|
|
2890
3223
|
]
|
|
2891
3224
|
])
|
|
@@ -2893,7 +3226,7 @@ async function packageLambda(options) {
|
|
|
2893
3226
|
);
|
|
2894
3227
|
await writeFile3(lambdaPath, zipSync(archive));
|
|
2895
3228
|
await rm(runtimeDir, { recursive: true, force: true });
|
|
2896
|
-
const lambdaChecksum = sha256(await
|
|
3229
|
+
const lambdaChecksum = sha256(await readFile5(lambdaPath));
|
|
2897
3230
|
const deploymentChecksum = sha256(JSON.stringify(runtimeMetadata));
|
|
2898
3231
|
const packagedRelease = {
|
|
2899
3232
|
...runtimeMetadata,
|
|
@@ -2914,7 +3247,6 @@ async function packageLambda(options) {
|
|
|
2914
3247
|
}
|
|
2915
3248
|
async function packageEcs(options) {
|
|
2916
3249
|
const outputDir = resolve2(options.outputDir);
|
|
2917
|
-
await mkdir2(outputDir, { recursive: true });
|
|
2918
3250
|
const imageReference = requireImageDigest(options.imageReference ?? "");
|
|
2919
3251
|
const release = await assembleRelease({
|
|
2920
3252
|
boardConfigPath: options.boardConfigPath,
|
|
@@ -2943,13 +3275,13 @@ async function packageEcs(options) {
|
|
|
2943
3275
|
);
|
|
2944
3276
|
await writeFile3(
|
|
2945
3277
|
join2(outputDir, "SHA256SUMS"),
|
|
2946
|
-
`${sha256(await
|
|
3278
|
+
`${sha256(await readFile5(join2(outputDir, "release.json")))} release.json
|
|
2947
3279
|
`
|
|
2948
3280
|
);
|
|
2949
3281
|
return packagedRelease;
|
|
2950
3282
|
}
|
|
2951
3283
|
async function cloudFormationTemplate(mode = "lambda") {
|
|
2952
|
-
return
|
|
3284
|
+
return readFile5(
|
|
2953
3285
|
fileURLToPath2(
|
|
2954
3286
|
new URL(mode === "ecs" ? "../template-ecs.yml" : "../template.yml", import.meta.url)
|
|
2955
3287
|
),
|
|
@@ -2991,8 +3323,8 @@ async function templateContract(parameters) {
|
|
|
2991
3323
|
)?.[0];
|
|
2992
3324
|
const metadataBlock = template.match(/^Metadata:\n[\s\S]*?(?=^Parameters:\s*$)/m)?.[0];
|
|
2993
3325
|
if (!parametersBlock) throw new Error("template has no Parameters block");
|
|
2994
|
-
const parsedParameters =
|
|
2995
|
-
const parsedMetadata = metadataBlock ?
|
|
3326
|
+
const parsedParameters = parse(parametersBlock);
|
|
3327
|
+
const parsedMetadata = metadataBlock ? parse(metadataBlock) : {};
|
|
2996
3328
|
const definitions = parsedParameters.Parameters ?? {};
|
|
2997
3329
|
const managedValue = parsedMetadata.Metadata?.PackageManagedParameters ?? [];
|
|
2998
3330
|
if (!Array.isArray(managedValue) || !managedValue.every((key) => typeof key === "string"))
|
|
@@ -3054,7 +3386,7 @@ async function runDoctor(options, dependencies = actualDependencies) {
|
|
|
3054
3386
|
let parameterData;
|
|
3055
3387
|
await check("Parameters/template", async () => {
|
|
3056
3388
|
const parameters = readParameterValues(
|
|
3057
|
-
JSON.parse(await
|
|
3389
|
+
JSON.parse(await readFile6(options.parametersPath, "utf8"))
|
|
3058
3390
|
);
|
|
3059
3391
|
parameterData = await templateContract(parameters);
|
|
3060
3392
|
return `${options.parametersPath} is compatible (${computeMode({ mode: parameterData.values.ComputeMode })})`;
|
|
@@ -3094,7 +3426,7 @@ async function runDoctor(options, dependencies = actualDependencies) {
|
|
|
3094
3426
|
const template = await bootstrapTemplate("github-oidc");
|
|
3095
3427
|
const expectedRevision = bootstrapTemplateRevision(template);
|
|
3096
3428
|
await check("Bootstrap template", async () => {
|
|
3097
|
-
const raw = JSON.parse(await
|
|
3429
|
+
const raw = JSON.parse(await readFile6(stackPath, "utf8"));
|
|
3098
3430
|
const stack = raw && typeof raw === "object" && "Stacks" in raw ? raw.Stacks?.[0] : raw;
|
|
3099
3431
|
if (!stack || typeof stack !== "object")
|
|
3100
3432
|
throw new Error("captured stack JSON contains no stack");
|
|
@@ -3132,7 +3464,7 @@ var option = (name, fallback) => {
|
|
|
3132
3464
|
};
|
|
3133
3465
|
async function installedPackageVersion() {
|
|
3134
3466
|
const packageManifest = JSON.parse(
|
|
3135
|
-
await
|
|
3467
|
+
await readFile7(new URL("../package.json", import.meta.url), "utf8")
|
|
3136
3468
|
);
|
|
3137
3469
|
return typeof packageManifest.version === "string" ? packageManifest.version : "";
|
|
3138
3470
|
}
|
|
@@ -3146,7 +3478,7 @@ function parameter(key, value2) {
|
|
|
3146
3478
|
}
|
|
3147
3479
|
async function existingParameters(path, allowMissing = false) {
|
|
3148
3480
|
try {
|
|
3149
|
-
const parsed = JSON.parse(await
|
|
3481
|
+
const parsed = JSON.parse(await readFile7(path, "utf8"));
|
|
3150
3482
|
if (!Array.isArray(parsed)) throw new Error(`${path} must contain a JSON parameter array`);
|
|
3151
3483
|
const values = parsed.map((value2) => {
|
|
3152
3484
|
if (!value2 || typeof value2 !== "object" || typeof value2.ParameterKey !== "string" || typeof value2.ParameterValue !== "string")
|
|
@@ -3170,7 +3502,7 @@ function bootstrapKind() {
|
|
|
3170
3502
|
throw new Error("--kind must be core or github-oidc");
|
|
3171
3503
|
}
|
|
3172
3504
|
async function readBootstrapConfig(path) {
|
|
3173
|
-
const parsed = JSON.parse(await
|
|
3505
|
+
const parsed = JSON.parse(await readFile7(path, "utf8"));
|
|
3174
3506
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
3175
3507
|
throw new Error("--config must contain a JSON object");
|
|
3176
3508
|
return parsed;
|
|
@@ -3251,10 +3583,10 @@ async function templateParameters(mode = "lambda") {
|
|
|
3251
3583
|
const template = await cloudFormationTemplate(mode);
|
|
3252
3584
|
const block = template.match(/^Parameters:\n[\s\S]*?(?=^[A-Za-z][A-Za-z0-9]*:\s*$)/m)?.[0];
|
|
3253
3585
|
if (!block) throw new Error("Unable to read Parameters from the CloudFormation template");
|
|
3254
|
-
const parsed =
|
|
3586
|
+
const parsed = parse2(block);
|
|
3255
3587
|
if (!parsed.Parameters) throw new Error("CloudFormation template has no Parameters");
|
|
3256
3588
|
const metadataBlock = template.match(/^Metadata:\n[\s\S]*?(?=^Parameters:\s*$)/m)?.[0];
|
|
3257
|
-
const metadata = metadataBlock ?
|
|
3589
|
+
const metadata = metadataBlock ? parse2(metadataBlock).Metadata ?? {} : {};
|
|
3258
3590
|
if (metadata.PackageManagedParameters !== void 0 && (!Array.isArray(metadata.PackageManagedParameters) || !metadata.PackageManagedParameters.every((key) => typeof key === "string")))
|
|
3259
3591
|
throw new Error("CloudFormation template has invalid PackageManagedParameters metadata");
|
|
3260
3592
|
const packageManaged = new Set(metadata.PackageManagedParameters ?? []);
|
|
@@ -3428,7 +3760,7 @@ try {
|
|
|
3428
3760
|
if (action === "init") {
|
|
3429
3761
|
const output = requiredOption("--output");
|
|
3430
3762
|
try {
|
|
3431
|
-
await
|
|
3763
|
+
await readFile7(output, "utf8");
|
|
3432
3764
|
throw new Error(`Refusing to overwrite existing manifest: ${output}`);
|
|
3433
3765
|
} catch (error) {
|
|
3434
3766
|
if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT"))
|
|
@@ -3486,9 +3818,9 @@ Review and commit this manifest before deployment.`
|
|
|
3486
3818
|
config,
|
|
3487
3819
|
configPath,
|
|
3488
3820
|
workDir: option("--work-dir"),
|
|
3489
|
-
coreStack: coreStackPath ? JSON.parse(await
|
|
3821
|
+
coreStack: coreStackPath ? JSON.parse(await readFile7(coreStackPath, "utf8")) : void 0,
|
|
3490
3822
|
coreStackPath,
|
|
3491
|
-
githubOidcStack: githubStackPath ? JSON.parse(await
|
|
3823
|
+
githubOidcStack: githubStackPath ? JSON.parse(await readFile7(githubStackPath, "utf8")) : void 0,
|
|
3492
3824
|
githubOidcStackPath: githubStackPath,
|
|
3493
3825
|
runner
|
|
3494
3826
|
});
|
|
@@ -3510,9 +3842,9 @@ Review and commit this manifest before deployment.`
|
|
|
3510
3842
|
config,
|
|
3511
3843
|
configPath,
|
|
3512
3844
|
workDir: option("--work-dir"),
|
|
3513
|
-
coreStack: coreStackPath ? JSON.parse(await
|
|
3845
|
+
coreStack: coreStackPath ? JSON.parse(await readFile7(coreStackPath, "utf8")) : void 0,
|
|
3514
3846
|
coreStackPath,
|
|
3515
|
-
githubOidcStack: githubStackPath ? JSON.parse(await
|
|
3847
|
+
githubOidcStack: githubStackPath ? JSON.parse(await readFile7(githubStackPath, "utf8")) : void 0,
|
|
3516
3848
|
githubOidcStackPath: githubStackPath,
|
|
3517
3849
|
runner
|
|
3518
3850
|
});
|
|
@@ -3527,8 +3859,8 @@ ${formatBootstrapRemediationText(handoff.remediation).join("\n")}`
|
|
|
3527
3859
|
const githubStackPath = requiredOption("--github-oidc-stack-json");
|
|
3528
3860
|
const verified = await verifyBootstrap({
|
|
3529
3861
|
config,
|
|
3530
|
-
coreStack: JSON.parse(await
|
|
3531
|
-
githubOidcStack: JSON.parse(await
|
|
3862
|
+
coreStack: JSON.parse(await readFile7(coreStackPath, "utf8")),
|
|
3863
|
+
githubOidcStack: JSON.parse(await readFile7(githubStackPath, "utf8"))
|
|
3532
3864
|
});
|
|
3533
3865
|
printBootstrap(
|
|
3534
3866
|
verified,
|
|
@@ -3612,7 +3944,7 @@ ${plan.notes.join("\n")}`);
|
|
|
3612
3944
|
if (kind === "github-oidc" && coreStackPath) {
|
|
3613
3945
|
coreOutputs = coreBootstrapOutputs(
|
|
3614
3946
|
deployedBootstrapStack(
|
|
3615
|
-
JSON.parse(await
|
|
3947
|
+
JSON.parse(await readFile7(coreStackPath, "utf8")),
|
|
3616
3948
|
bootstrapContractVersion(await bootstrapTemplate("core", mode))
|
|
3617
3949
|
)
|
|
3618
3950
|
);
|
|
@@ -3625,7 +3957,7 @@ ${plan.notes.join("\n")}`);
|
|
|
3625
3957
|
const deployedStackPath = option("--deployed-stack-json");
|
|
3626
3958
|
if (deployedStackPath) {
|
|
3627
3959
|
const stack = deployedBootstrapStack(
|
|
3628
|
-
JSON.parse(await
|
|
3960
|
+
JSON.parse(await readFile7(deployedStackPath, "utf8")),
|
|
3629
3961
|
bootstrapContractVersion(await bootstrapTemplate(kind, mode))
|
|
3630
3962
|
);
|
|
3631
3963
|
if (kind === "github-oidc" && !(stack.Parameters ?? []).some(
|