@deployfoundation/foundation-deploy 0.2.37 → 0.2.39
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/app.js +3 -2
- package/dist/bin/foundation-deploy.js +503 -100
- package/dist/bin/release-account.js +1 -2
- package/dist/{chunk-9yz4hnte.js → chunk-6v0ewr5b.js} +20 -5
- package/dist/{chunk-hps5vshg.js → chunk-7rd8c1th.js} +28 -2
- package/dist/chunk-dz91avrb.js +16 -0
- package/dist/src/index.js +5 -2
- package/package.json +1 -1
- package/src/artifacts.ts +33 -0
- package/src/deploy/release.ts +1 -35
- package/src/deploy-permissions.ts +37 -2
- package/src/index.ts +2 -0
- package/src/release/trust.ts +52 -0
- package/src/stacks/api-stack.ts +2 -1
- package/src/stacks/ci-stack.ts +2 -1
- package/src/stacks/pipeline-stack.ts +2 -1
- package/dist/chunk-gmdzzrc4.js +0 -442
package/dist/chunk-gmdzzrc4.js
DELETED
|
@@ -1,442 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
RELEASE_BUCKET_ENV,
|
|
3
|
-
RELEASE_VERSION_RE,
|
|
4
|
-
instanceNames,
|
|
5
|
-
loadInstanceFile,
|
|
6
|
-
manifestKey,
|
|
7
|
-
releaseCacheDir,
|
|
8
|
-
verifyManifest
|
|
9
|
-
} from "./chunk-hps5vshg.js";
|
|
10
|
-
|
|
11
|
-
// src/deploy/release.ts
|
|
12
|
-
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2 } from "node:fs";
|
|
13
|
-
import { dirname as dirname3, isAbsolute, join as join2, resolve as resolve2 } from "node:path";
|
|
14
|
-
|
|
15
|
-
// src/release/kms.ts
|
|
16
|
-
import { KMSClient, SignCommand, VerifyCommand } from "@aws-sdk/client-kms";
|
|
17
|
-
function regionOfKeyArn(keyArn) {
|
|
18
|
-
const region = keyArn.split(":")[3];
|
|
19
|
-
if (region === undefined || region === "")
|
|
20
|
-
throw new Error(`not a KMS key ARN: ${keyArn} (expected arn:aws:kms:<region>:<account>:key/…)`);
|
|
21
|
-
return region;
|
|
22
|
-
}
|
|
23
|
-
function client(keyArn, options = {}) {
|
|
24
|
-
const profile = options.profile ?? "";
|
|
25
|
-
return new KMSClient({
|
|
26
|
-
region: regionOfKeyArn(keyArn),
|
|
27
|
-
...profile === "" ? {} : { profile }
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
function kmsVerifier(keyArn, options = {}) {
|
|
31
|
-
const kms = client(keyArn, options);
|
|
32
|
-
return {
|
|
33
|
-
async verify(input) {
|
|
34
|
-
const result = await kms.send(new VerifyCommand(input));
|
|
35
|
-
return {
|
|
36
|
-
...result.SignatureValid === undefined ? {} : { SignatureValid: result.SignatureValid }
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// src/deploy/aws.ts
|
|
43
|
-
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
44
|
-
import { tmpdir } from "node:os";
|
|
45
|
-
import { join } from "node:path";
|
|
46
|
-
|
|
47
|
-
// src/deploy/instance.ts
|
|
48
|
-
import { dirname } from "node:path";
|
|
49
|
-
var INSTANCE_FILE_ENV = "FOUNDATION_INSTANCE_FILE";
|
|
50
|
-
function resolveInstanceFilePath(argv = [], env = {}) {
|
|
51
|
-
for (let i = 0;i < argv.length; i++) {
|
|
52
|
-
const arg = argv[i] ?? "";
|
|
53
|
-
if (arg === "--instance") {
|
|
54
|
-
const next = argv[i + 1];
|
|
55
|
-
if (next === undefined || next.startsWith("-"))
|
|
56
|
-
throw new Error("--instance needs a path, e.g. --instance .foundation/instance.yaml");
|
|
57
|
-
return next;
|
|
58
|
-
}
|
|
59
|
-
if (arg.startsWith("--instance=")) {
|
|
60
|
-
const value = arg.slice("--instance=".length);
|
|
61
|
-
if (value === "")
|
|
62
|
-
throw new Error("--instance needs a path");
|
|
63
|
-
return value;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
const fromEnv = env[INSTANCE_FILE_ENV];
|
|
67
|
-
if (fromEnv !== undefined && fromEnv !== "")
|
|
68
|
-
return fromEnv;
|
|
69
|
-
throw new Error(`--instance <path> is required (or set ${INSTANCE_FILE_ENV}); it is the path to the deployment's instance YAML`);
|
|
70
|
-
}
|
|
71
|
-
function loadInstanceContext(path, cwd = process.cwd()) {
|
|
72
|
-
const file = loadInstanceFile(path, cwd);
|
|
73
|
-
return { ...file, root: dirname(file.path) };
|
|
74
|
-
}
|
|
75
|
-
function loadInstanceFromArgs(argv = process.argv.slice(2), env = process.env) {
|
|
76
|
-
return loadInstanceContext(resolveInstanceFilePath(argv, env));
|
|
77
|
-
}
|
|
78
|
-
function instanceBanner(context) {
|
|
79
|
-
const { instance } = context;
|
|
80
|
-
return `instance: ${instance.name} (account ${instance.aws.account}, region ${instance.aws.region})
|
|
81
|
-
file: ${context.path}
|
|
82
|
-
config: ${context.configPath}`;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// src/deploy/sh.ts
|
|
86
|
-
import { spawn as nodeSpawn } from "node:child_process";
|
|
87
|
-
function formatCommand(cmd, env) {
|
|
88
|
-
const prefix = Object.entries(env ?? {}).map(([k, v]) => `${k}=${quote(v)}`).join(" ");
|
|
89
|
-
const body = cmd.map(quote).join(" ");
|
|
90
|
-
return prefix === "" ? body : `${prefix} ${body}`;
|
|
91
|
-
}
|
|
92
|
-
function quote(value) {
|
|
93
|
-
return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value) ? value : `'${value.replaceAll("'", `'\\''`)}'`;
|
|
94
|
-
}
|
|
95
|
-
function start(cmd, opts, stdout) {
|
|
96
|
-
const [bin, ...rest] = cmd;
|
|
97
|
-
if (bin === undefined)
|
|
98
|
-
throw new Error("run: empty command");
|
|
99
|
-
const child = nodeSpawn(bin, rest, {
|
|
100
|
-
cwd: opts.cwd,
|
|
101
|
-
env: { ...process.env, ...opts.env },
|
|
102
|
-
stdio: [
|
|
103
|
-
opts.stdin === undefined ? "ignore" : "pipe",
|
|
104
|
-
stdout,
|
|
105
|
-
stdout === "inherit" ? "inherit" : "pipe"
|
|
106
|
-
]
|
|
107
|
-
});
|
|
108
|
-
if (opts.stdin !== undefined && child.stdin !== null) {
|
|
109
|
-
child.stdin.end(opts.stdin);
|
|
110
|
-
}
|
|
111
|
-
return child;
|
|
112
|
-
}
|
|
113
|
-
function exited(child) {
|
|
114
|
-
return new Promise((resolve, reject) => {
|
|
115
|
-
child.once("error", reject);
|
|
116
|
-
child.once("close", (code, signal) => resolve(code ?? (signal === null ? 1 : 128)));
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
function collect(stream) {
|
|
120
|
-
if (stream === null)
|
|
121
|
-
return Promise.resolve("");
|
|
122
|
-
return new Promise((resolve, reject) => {
|
|
123
|
-
const chunks = [];
|
|
124
|
-
stream.on("data", (c) => chunks.push(c));
|
|
125
|
-
stream.once("error", reject);
|
|
126
|
-
stream.once("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
async function run(cmd, opts = {}) {
|
|
130
|
-
if (opts.dryRun === true) {
|
|
131
|
-
console.log(` $ ${formatCommand(cmd, opts.env)}`);
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
const code = await exited(start(cmd, opts, "inherit"));
|
|
135
|
-
if (code !== 0)
|
|
136
|
-
throw new Error(`${formatCommand(cmd)} exited ${code}`);
|
|
137
|
-
}
|
|
138
|
-
async function runCapture(cmd, opts = {}) {
|
|
139
|
-
const child = start(cmd, opts, "pipe");
|
|
140
|
-
const [out, err, code] = await Promise.all([
|
|
141
|
-
collect(child.stdout),
|
|
142
|
-
collect(child.stderr),
|
|
143
|
-
exited(child)
|
|
144
|
-
]);
|
|
145
|
-
if (code !== 0)
|
|
146
|
-
throw new Error(`${formatCommand(cmd)} exited ${code}: ${err.trim()}`);
|
|
147
|
-
return out.trim();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// src/deploy/aws.ts
|
|
151
|
-
function resolveProfile(fallback, explicit, env = process.env) {
|
|
152
|
-
if (env.FOUNDATION_NO_PROFILE === "1")
|
|
153
|
-
return "";
|
|
154
|
-
if (explicit !== undefined)
|
|
155
|
-
return explicit;
|
|
156
|
-
if (env.AWS_PROFILE !== undefined && env.AWS_PROFILE !== "")
|
|
157
|
-
return env.AWS_PROFILE;
|
|
158
|
-
if (env.GITHUB_ACTIONS === "true")
|
|
159
|
-
return "";
|
|
160
|
-
return fallback;
|
|
161
|
-
}
|
|
162
|
-
function awsContext(overrides = {}) {
|
|
163
|
-
const env = overrides.env ?? process.env;
|
|
164
|
-
const paths = overrides.paths ?? loadInstanceFromArgs();
|
|
165
|
-
const instance = paths.instance;
|
|
166
|
-
return {
|
|
167
|
-
profile: resolveProfile(instance.aws.profile, overrides.profile, env),
|
|
168
|
-
region: overrides.region ?? env.AWS_REGION ?? instance.aws.region,
|
|
169
|
-
dryRun: overrides.dryRun ?? false,
|
|
170
|
-
instance,
|
|
171
|
-
paths,
|
|
172
|
-
names: instanceNames(instance)
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
function argv(ctx, args) {
|
|
176
|
-
const profile = ctx.profile === "" ? [] : ["--profile", ctx.profile];
|
|
177
|
-
return ["aws", ...args, ...profile, "--region", ctx.region];
|
|
178
|
-
}
|
|
179
|
-
function cdkEnv(ctx) {
|
|
180
|
-
return {
|
|
181
|
-
...ctx.profile === "" ? {} : { AWS_PROFILE: ctx.profile },
|
|
182
|
-
AWS_REGION: ctx.region,
|
|
183
|
-
CDK_DEFAULT_REGION: ctx.region
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
async function aws(ctx, args, stdin) {
|
|
187
|
-
return runCapture(argv(ctx, args), { stdin });
|
|
188
|
-
}
|
|
189
|
-
async function awsMutate(ctx, args, stdin) {
|
|
190
|
-
if (ctx.dryRun === true) {
|
|
191
|
-
console.log(` $ ${argv(ctx, args).join(" ")}${stdin === undefined ? "" : " < (stdin)"}`);
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
await run(argv(ctx, args), { stdin });
|
|
195
|
-
}
|
|
196
|
-
async function stackOutput(ctx, stack, key) {
|
|
197
|
-
const value = await aws(ctx, [
|
|
198
|
-
"cloudformation",
|
|
199
|
-
"describe-stacks",
|
|
200
|
-
"--stack-name",
|
|
201
|
-
stack,
|
|
202
|
-
"--query",
|
|
203
|
-
`Stacks[0].Outputs[?OutputKey=='${key}'].OutputValue`,
|
|
204
|
-
"--output",
|
|
205
|
-
"text"
|
|
206
|
-
]);
|
|
207
|
-
if (value === "" || value === "None")
|
|
208
|
-
throw new Error(`stack ${stack} has no output ${key} — has it been deployed?`);
|
|
209
|
-
return value;
|
|
210
|
-
}
|
|
211
|
-
async function stackExists(ctx, stack) {
|
|
212
|
-
try {
|
|
213
|
-
await aws(ctx, [
|
|
214
|
-
"cloudformation",
|
|
215
|
-
"describe-stacks",
|
|
216
|
-
"--stack-name",
|
|
217
|
-
stack,
|
|
218
|
-
"--output",
|
|
219
|
-
"text"
|
|
220
|
-
]);
|
|
221
|
-
return true;
|
|
222
|
-
} catch {
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
async function secretExists(ctx, secretId) {
|
|
227
|
-
try {
|
|
228
|
-
await aws(ctx, [
|
|
229
|
-
"secretsmanager",
|
|
230
|
-
"describe-secret",
|
|
231
|
-
"--secret-id",
|
|
232
|
-
secretId,
|
|
233
|
-
"--output",
|
|
234
|
-
"text"
|
|
235
|
-
]);
|
|
236
|
-
return true;
|
|
237
|
-
} catch {
|
|
238
|
-
return false;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
async function readSecretString(ctx, secretId) {
|
|
242
|
-
return aws(ctx, [
|
|
243
|
-
"secretsmanager",
|
|
244
|
-
"get-secret-value",
|
|
245
|
-
"--secret-id",
|
|
246
|
-
secretId,
|
|
247
|
-
"--query",
|
|
248
|
-
"SecretString",
|
|
249
|
-
"--output",
|
|
250
|
-
"text"
|
|
251
|
-
]);
|
|
252
|
-
}
|
|
253
|
-
async function readSecretJson(ctx, secretId) {
|
|
254
|
-
return JSON.parse(await readSecretString(ctx, secretId));
|
|
255
|
-
}
|
|
256
|
-
async function putSecretString(ctx, secretId, value) {
|
|
257
|
-
await throughSecretFile(value, (file) => awsMutate(ctx, [
|
|
258
|
-
"secretsmanager",
|
|
259
|
-
"put-secret-value",
|
|
260
|
-
"--secret-id",
|
|
261
|
-
secretId,
|
|
262
|
-
"--secret-string",
|
|
263
|
-
`file://${file}`
|
|
264
|
-
]));
|
|
265
|
-
}
|
|
266
|
-
async function createSecretString(ctx, secretId, value, description) {
|
|
267
|
-
await throughSecretFile(value, (file) => awsMutate(ctx, [
|
|
268
|
-
"secretsmanager",
|
|
269
|
-
"create-secret",
|
|
270
|
-
"--name",
|
|
271
|
-
secretId,
|
|
272
|
-
"--description",
|
|
273
|
-
description,
|
|
274
|
-
"--secret-string",
|
|
275
|
-
`file://${file}`
|
|
276
|
-
]));
|
|
277
|
-
}
|
|
278
|
-
async function throughSecretFile(value, body) {
|
|
279
|
-
const dir = mkdtempSync(join(tmpdir(), "foundation-secret-"));
|
|
280
|
-
const file = join(dir, "value.json");
|
|
281
|
-
try {
|
|
282
|
-
writeFileSync(file, value, { mode: 384 });
|
|
283
|
-
await body(file);
|
|
284
|
-
} finally {
|
|
285
|
-
rmSync(dir, { recursive: true, force: true });
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
async function putSecretJson(ctx, secretId, value) {
|
|
289
|
-
await putSecretString(ctx, secretId, JSON.stringify(value));
|
|
290
|
-
}
|
|
291
|
-
async function callerAccountId(ctx) {
|
|
292
|
-
return aws(ctx, ["sts", "get-caller-identity", "--query", "Account", "--output", "text"]);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// src/deploy/paths.ts
|
|
296
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
297
|
-
import { dirname as dirname2, resolve } from "node:path";
|
|
298
|
-
import { fileURLToPath } from "node:url";
|
|
299
|
-
var PACKAGE_NAME = "@deployfoundation/foundation-deploy";
|
|
300
|
-
function packageRoot(from) {
|
|
301
|
-
let dir = from;
|
|
302
|
-
for (;; ) {
|
|
303
|
-
const manifest = resolve(dir, "package.json");
|
|
304
|
-
if (existsSync(manifest)) {
|
|
305
|
-
try {
|
|
306
|
-
const { name } = JSON.parse(readFileSync(manifest, "utf8"));
|
|
307
|
-
if (name === PACKAGE_NAME)
|
|
308
|
-
return dir;
|
|
309
|
-
} catch {}
|
|
310
|
-
}
|
|
311
|
-
const parent = dirname2(dir);
|
|
312
|
-
if (parent === dir)
|
|
313
|
-
throw new Error(`cannot find the ${PACKAGE_NAME} package root above ${from}`);
|
|
314
|
-
dir = parent;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
var INFRA_ROOT = packageRoot(dirname2(fileURLToPath(import.meta.url)));
|
|
318
|
-
var FOUNDATION_ROOT = resolve(INFRA_ROOT, "..", "..");
|
|
319
|
-
var AGENT_DOCKERFILE = "packages/infra/agent-image/Dockerfile";
|
|
320
|
-
var PACKAGE_ASSETS = resolve(INFRA_ROOT, "src", "deploy", "assets");
|
|
321
|
-
|
|
322
|
-
// src/deploy/release.ts
|
|
323
|
-
var DEFAULT_RELEASE_BUCKET = "foundry41-foundation-releases";
|
|
324
|
-
var RELEASE_KMS_KEY_ARN_ENV = "FOUNDATION_RELEASE_KMS_KEY_ARN";
|
|
325
|
-
var RELEASE_KMS_KEY_ARN = "arn:aws:kms:us-east-1:793593623536:key/fba7d9f3-e9b6-49ae-b4a5-c8c5f1429231";
|
|
326
|
-
function flag(args, name) {
|
|
327
|
-
const index = args.indexOf(name);
|
|
328
|
-
const value = index === -1 ? undefined : args[index + 1];
|
|
329
|
-
if (value?.startsWith("-") === true)
|
|
330
|
-
throw new Error(`${name} needs a value, e.g. ${name} ${name === "--release" ? "v0.1.0" : "…"}`);
|
|
331
|
-
const inline = args.find((arg) => arg.startsWith(`${name}=`));
|
|
332
|
-
return value ?? (inline === undefined ? undefined : inline.slice(name.length + 1));
|
|
333
|
-
}
|
|
334
|
-
function toolVersion(infraRoot = INFRA_ROOT) {
|
|
335
|
-
const { version } = JSON.parse(readFileSync2(join2(infraRoot, "package.json"), "utf8"));
|
|
336
|
-
return version;
|
|
337
|
-
}
|
|
338
|
-
function foundationVersion(release) {
|
|
339
|
-
return release?.version ?? `v${toolVersion()}`;
|
|
340
|
-
}
|
|
341
|
-
function hasFoundationWorkspace(foundationRoot = FOUNDATION_ROOT) {
|
|
342
|
-
return existsSync2(join2(foundationRoot, "packages", "gateway", "package.json"));
|
|
343
|
-
}
|
|
344
|
-
function releaseRequest(args, options = {}) {
|
|
345
|
-
const env = options.env ?? process.env;
|
|
346
|
-
const bucket = flag(args, "--release-bucket") ?? env[RELEASE_BUCKET_ENV] ?? DEFAULT_RELEASE_BUCKET;
|
|
347
|
-
const manifestRef = flag(args, "--manifest");
|
|
348
|
-
const explicit = flag(args, "--release");
|
|
349
|
-
if (explicit !== undefined) {
|
|
350
|
-
if (!RELEASE_VERSION_RE.test(explicit))
|
|
351
|
-
throw new Error(`--release wants a version like v0.1.0, not "${explicit}"`);
|
|
352
|
-
return { version: explicit, bucket, ...manifestRef === undefined ? {} : { manifestRef } };
|
|
353
|
-
}
|
|
354
|
-
if (manifestRef !== undefined)
|
|
355
|
-
return { manifestRef, bucket };
|
|
356
|
-
const workspace = options.workspace ?? hasFoundationWorkspace();
|
|
357
|
-
if (workspace)
|
|
358
|
-
return;
|
|
359
|
-
const version = `v${options.version ?? toolVersion()}`;
|
|
360
|
-
if (!RELEASE_VERSION_RE.test(version))
|
|
361
|
-
throw new Error(`this copy of foundation-deploy is version ${version.slice(1)}, which is not a release; pass --release <version>`);
|
|
362
|
-
return { version, bucket };
|
|
363
|
-
}
|
|
364
|
-
function expectedKeyArn(env = process.env) {
|
|
365
|
-
const configured = env[RELEASE_KMS_KEY_ARN_ENV] ?? RELEASE_KMS_KEY_ARN;
|
|
366
|
-
if (configured === undefined || configured === "")
|
|
367
|
-
throw new Error(`no Foundation release signing key is configured; set ${RELEASE_KMS_KEY_ARN_ENV} to the key ARN published with the release`);
|
|
368
|
-
return configured;
|
|
369
|
-
}
|
|
370
|
-
async function s3Download(ctx, bucket, key, dest) {
|
|
371
|
-
mkdirSync(dirname3(dest), { recursive: true });
|
|
372
|
-
await aws(ctx, ["s3", "cp", `s3://${bucket}/${key}`, dest]);
|
|
373
|
-
}
|
|
374
|
-
async function verifyRelease(ctx, request, deps = {}) {
|
|
375
|
-
const env = deps.env ?? process.env;
|
|
376
|
-
const kmsKeyArn = deps.kmsKeyArn ?? expectedKeyArn(env);
|
|
377
|
-
const download = deps.download ?? s3Download;
|
|
378
|
-
const local = localManifestRef(request);
|
|
379
|
-
const version = request.version;
|
|
380
|
-
const cacheDir = deps.cacheDir ?? releaseCacheDir(version ?? "unversioned", env);
|
|
381
|
-
const manifestPath = local ?? join2(cacheDir, "manifest.json");
|
|
382
|
-
if (local === undefined) {
|
|
383
|
-
const source = s3ManifestRef(request);
|
|
384
|
-
await download(ctx, source.bucket, source.key, manifestPath);
|
|
385
|
-
}
|
|
386
|
-
const manifest = await verifyManifest(JSON.parse(readFileSync2(manifestPath, "utf8")), {
|
|
387
|
-
kmsKeyArn,
|
|
388
|
-
kms: deps.kms ?? kmsVerifier(kmsKeyArn, ctx.profile === "" ? {} : { profile: ctx.profile }),
|
|
389
|
-
...version === undefined ? {} : { expectVersion: version },
|
|
390
|
-
...deps.verifyArtifacts === false ? {} : {
|
|
391
|
-
readArtifact: async (key) => {
|
|
392
|
-
const dest = join2(cacheDir, "artifacts", key.split("/").slice(-1)[0] ?? "artifact");
|
|
393
|
-
await download(ctx, request.bucket, key, dest);
|
|
394
|
-
return readFileSync2(dest);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
});
|
|
398
|
-
return { version: manifest.version, bucket: request.bucket, manifestPath, manifest };
|
|
399
|
-
}
|
|
400
|
-
async function resolveRelease(ctx, request, deps = {}) {
|
|
401
|
-
return ctx.dryRun === true ? plannedRelease(request) : verifyRelease(ctx, request, deps);
|
|
402
|
-
}
|
|
403
|
-
function plannedRelease(request) {
|
|
404
|
-
const version = request.version ?? "<from the manifest>";
|
|
405
|
-
const local = localManifestRef(request);
|
|
406
|
-
return {
|
|
407
|
-
version,
|
|
408
|
-
bucket: request.bucket,
|
|
409
|
-
manifestPath: local ?? join2(releaseCacheDir(version), "manifest.json")
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
function localManifestRef(request) {
|
|
413
|
-
const ref = request.manifestRef;
|
|
414
|
-
if (ref === undefined || ref.startsWith("s3://"))
|
|
415
|
-
return;
|
|
416
|
-
return isAbsolute(ref) ? ref : resolve2(process.cwd(), ref);
|
|
417
|
-
}
|
|
418
|
-
function s3ManifestRef(request) {
|
|
419
|
-
const ref = request.manifestRef;
|
|
420
|
-
if (ref?.startsWith("s3://") === true) {
|
|
421
|
-
const [bucket, ...rest] = ref.slice("s3://".length).split("/");
|
|
422
|
-
const key = rest.join("/");
|
|
423
|
-
if (bucket === undefined || bucket === "" || key === "")
|
|
424
|
-
throw new Error(`--manifest ${ref} is not an s3://bucket/key URI`);
|
|
425
|
-
return { bucket, key };
|
|
426
|
-
}
|
|
427
|
-
if (request.version === undefined)
|
|
428
|
-
throw new Error("a release needs a version or a manifest to fetch");
|
|
429
|
-
return { bucket: request.bucket, key: manifestKey(request.version) };
|
|
430
|
-
}
|
|
431
|
-
function releaseContext(release) {
|
|
432
|
-
return [
|
|
433
|
-
"-c",
|
|
434
|
-
`release=${release.version}`,
|
|
435
|
-
"-c",
|
|
436
|
-
`releaseManifest=${release.manifestPath}`,
|
|
437
|
-
"-c",
|
|
438
|
-
`releaseBucket=${release.bucket}`
|
|
439
|
-
];
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
export { resolveInstanceFilePath, loadInstanceContext, instanceBanner, run, runCapture, awsContext, argv, cdkEnv, aws, awsMutate, stackOutput, stackExists, secretExists, readSecretString, readSecretJson, putSecretString, createSecretString, putSecretJson, callerAccountId, INFRA_ROOT, FOUNDATION_ROOT, AGENT_DOCKERFILE, PACKAGE_ASSETS, DEFAULT_RELEASE_BUCKET, toolVersion, foundationVersion, hasFoundationWorkspace, releaseRequest, resolveRelease, releaseContext };
|