@caelo-cms/provisioning 0.10.29 → 0.10.31

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.
Files changed (99) hide show
  1. package/dist/admin-domain.d.ts +54 -0
  2. package/dist/admin-domain.d.ts.map +1 -0
  3. package/dist/admin-domain.js +122 -0
  4. package/dist/admin-domain.js.map +1 -0
  5. package/dist/cli.js +71 -7
  6. package/dist/cli.js.map +1 -1
  7. package/dist/compose.d.ts +7 -9
  8. package/dist/compose.d.ts.map +1 -1
  9. package/dist/compose.js +17 -1
  10. package/dist/compose.js.map +1 -1
  11. package/dist/deployed-release.d.ts +84 -0
  12. package/dist/deployed-release.d.ts.map +1 -0
  13. package/dist/deployed-release.js +182 -0
  14. package/dist/deployed-release.js.map +1 -0
  15. package/dist/gcloud-retry.d.ts +16 -0
  16. package/dist/gcloud-retry.d.ts.map +1 -0
  17. package/dist/gcloud-retry.js +17 -0
  18. package/dist/gcloud-retry.js.map +1 -0
  19. package/dist/gcloud.d.ts.map +1 -1
  20. package/dist/gcloud.js +2 -0
  21. package/dist/gcloud.js.map +1 -1
  22. package/dist/gcp-names.d.ts +58 -0
  23. package/dist/gcp-names.d.ts.map +1 -0
  24. package/dist/gcp-names.js +88 -0
  25. package/dist/gcp-names.js.map +1 -0
  26. package/dist/install-state.d.ts +31 -0
  27. package/dist/install-state.d.ts.map +1 -1
  28. package/dist/install-state.js +38 -0
  29. package/dist/install-state.js.map +1 -1
  30. package/dist/lifecycle.d.ts +5 -0
  31. package/dist/lifecycle.d.ts.map +1 -1
  32. package/dist/lifecycle.js +340 -50
  33. package/dist/lifecycle.js.map +1 -1
  34. package/dist/mcp-iap.d.ts +5 -26
  35. package/dist/mcp-iap.d.ts.map +1 -1
  36. package/dist/mcp-iap.js +6 -18
  37. package/dist/mcp-iap.js.map +1 -1
  38. package/dist/migration-runner.d.ts +25 -0
  39. package/dist/migration-runner.d.ts.map +1 -1
  40. package/dist/migration-runner.js +60 -19
  41. package/dist/migration-runner.js.map +1 -1
  42. package/dist/operator-access.d.ts +83 -0
  43. package/dist/operator-access.d.ts.map +1 -0
  44. package/dist/operator-access.js +562 -0
  45. package/dist/operator-access.js.map +1 -0
  46. package/dist/region-data.d.ts +30 -0
  47. package/dist/region-data.d.ts.map +1 -0
  48. package/dist/region-data.js +406 -0
  49. package/dist/region-data.js.map +1 -0
  50. package/dist/regions.d.ts +130 -0
  51. package/dist/regions.d.ts.map +1 -0
  52. package/dist/regions.js +247 -0
  53. package/dist/regions.js.map +1 -0
  54. package/dist/runtime-secrets.d.ts +128 -0
  55. package/dist/runtime-secrets.d.ts.map +1 -0
  56. package/dist/runtime-secrets.js +444 -0
  57. package/dist/runtime-secrets.js.map +1 -0
  58. package/dist/stack-contract.d.ts +231 -0
  59. package/dist/stack-contract.d.ts.map +1 -0
  60. package/dist/stack-contract.js +455 -0
  61. package/dist/stack-contract.js.map +1 -0
  62. package/dist/stack-converge.d.ts +183 -0
  63. package/dist/stack-converge.d.ts.map +1 -0
  64. package/dist/stack-converge.js +513 -0
  65. package/dist/stack-converge.js.map +1 -0
  66. package/dist/wizard.d.ts +7 -0
  67. package/dist/wizard.d.ts.map +1 -1
  68. package/dist/wizard.js +11 -1
  69. package/dist/wizard.js.map +1 -1
  70. package/dist/wizards/gcp-cost.d.ts +10 -10
  71. package/dist/wizards/gcp-cost.d.ts.map +1 -1
  72. package/dist/wizards/gcp-cost.js +40 -3
  73. package/dist/wizards/gcp-cost.js.map +1 -1
  74. package/dist/wizards/gcp-firebase.d.ts +2 -0
  75. package/dist/wizards/gcp-firebase.d.ts.map +1 -1
  76. package/dist/wizards/gcp-firebase.js +1 -0
  77. package/dist/wizards/gcp-firebase.js.map +1 -1
  78. package/dist/wizards/gcp-pulumi.d.ts +51 -1
  79. package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
  80. package/dist/wizards/gcp-pulumi.js +89 -6
  81. package/dist/wizards/gcp-pulumi.js.map +1 -1
  82. package/dist/wizards/gcp.d.ts +2 -0
  83. package/dist/wizards/gcp.d.ts.map +1 -1
  84. package/dist/wizards/gcp.js +171 -23
  85. package/dist/wizards/gcp.js.map +1 -1
  86. package/package.json +3 -3
  87. package/stacks/aws/Pulumi.yaml +5 -2
  88. package/stacks/aws/README.md +3 -1
  89. package/stacks/aws/index.ts +21 -1
  90. package/stacks/azure/Pulumi.yaml +6 -3
  91. package/stacks/azure/README.md +1 -1
  92. package/stacks/azure/index.ts +22 -3
  93. package/stacks/gcp/Pulumi.yaml +5 -5
  94. package/stacks/gcp/README.md +15 -3
  95. package/stacks/gcp/index.ts +204 -141
  96. package/stacks/gcp-firebase/Pulumi.yaml +5 -2
  97. package/stacks/gcp-firebase/index.ts +169 -76
  98. package/stacks/self-hosted/Pulumi.yaml +4 -0
  99. package/stacks/self-hosted/index.ts +3 -0
@@ -0,0 +1,444 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * The runtime identities and secrets of a GCP install that the CLI (not
4
+ * Pulumi) creates and maintains, through gcloud:
5
+ *
6
+ * - {@link ensureGatewayServiceAccount}: the gateway's own run SA, so it
7
+ * can be granted only the secrets the gateway reads.
8
+ * - {@link ensureGeneratedSecrets}: the secrets in
9
+ * `CLI_GENERATED_SECRETS` (stack-contract.ts). The wizard runs it before
10
+ * `pulumi up`, upgrade on every roll, so installs that predate a secret
11
+ * get it without operator action. Values are generated here and go to
12
+ * Secret Manager on stdin — never on argv, never to disk.
13
+ * - {@link rotateRuntimeSecret}: `cms-provision rotate-secret`.
14
+ *
15
+ * Every function reports instead of throwing on a gcloud failure.
16
+ */
17
+ import { randomBytes } from "node:crypto";
18
+ import { gcloud as defaultGcloud } from "./gcloud.js";
19
+ import { realSleep, runWithRetry } from "./gcloud-retry.js";
20
+ import { gatewayServiceAccountEmail, gatewayServiceAccountId, gcpSecretId } from "./gcp-names.js";
21
+ import { CLI_GENERATED_SECRETS, SERVICE_SECRET_ENV, serviceSecrets, } from "./stack-contract.js";
22
+ import { liveContainerEnv } from "./stack-converge.js";
23
+ /** 32 random bytes as hex — the shape of every secret the stacks generate. */
24
+ export function generateSecretValue() {
25
+ return randomBytes(32).toString("hex");
26
+ }
27
+ const NOT_FOUND = /NOT_FOUND|not found|does not exist/i;
28
+ const ALREADY_EXISTS = /ALREADY_EXISTS|already exists/i;
29
+ // ===========================================================================
30
+ // Gateway service account
31
+ // ===========================================================================
32
+ /** Create the gateway's run SA unless it exists. */
33
+ export async function ensureGatewayServiceAccount(install, deps = {}) {
34
+ const run = deps.run ?? defaultGcloud;
35
+ const email = gatewayServiceAccountEmail(install.projectId, install.env);
36
+ const id = `service account ${email}`;
37
+ const project = `--project=${install.projectId}`;
38
+ const describe = await run([
39
+ "iam",
40
+ "service-accounts",
41
+ "describe",
42
+ email,
43
+ project,
44
+ "--format=value(email)",
45
+ ]);
46
+ if (describe.ok)
47
+ return { id, status: "present" };
48
+ if (!NOT_FOUND.test(describe.stderr)) {
49
+ return { id, status: "failed", error: describe.stderr.trim() };
50
+ }
51
+ const create = await run([
52
+ "iam",
53
+ "service-accounts",
54
+ "create",
55
+ gatewayServiceAccountId(install.env),
56
+ project,
57
+ `--display-name=Caelo ${install.env} gateway`,
58
+ "--quiet",
59
+ ]);
60
+ if (create.ok || ALREADY_EXISTS.test(create.stderr))
61
+ return { id, status: "applied" };
62
+ return { id, status: "failed", error: create.stderr.trim() };
63
+ }
64
+ // ===========================================================================
65
+ // Generated secrets
66
+ // ===========================================================================
67
+ /**
68
+ * Values of CLI-generated secrets a service runs with as plain env vars,
69
+ * for {@link ensureGeneratedSecrets}'s `seed`.
70
+ */
71
+ export function plainGeneratedSecretSeed(liveEnv) {
72
+ const seed = {};
73
+ for (const [name, secret] of Object.entries(SERVICE_SECRET_ENV.admin)) {
74
+ const generated = CLI_GENERATED_SECRETS.find((g) => g === secret);
75
+ const live = liveEnv.get(name);
76
+ if (generated && live?.kind === "value" && live.value)
77
+ seed[generated] = live.value;
78
+ }
79
+ return seed;
80
+ }
81
+ /** The stacks' `secretReplication` config value as a {@link SecretReplication}. */
82
+ export function stackSecretReplication(mode, region) {
83
+ return mode === "auto" ? { kind: "automatic" } : { kind: "user-managed", locations: [region] };
84
+ }
85
+ /**
86
+ * The replication of the install's existing `postgres-password` secret, so
87
+ * secrets created later match what the stack pinned (orgs with a
88
+ * `gcp.resourceLocations` policy reject `automatic`).
89
+ */
90
+ export async function readSecretReplication(install, deps = {}) {
91
+ const run = deps.run ?? defaultGcloud;
92
+ const secretId = gcpSecretId(install.env, "postgres-password");
93
+ const r = await run([
94
+ "secrets",
95
+ "describe",
96
+ secretId,
97
+ `--project=${install.projectId}`,
98
+ "--format=json",
99
+ ]);
100
+ if (!r.ok)
101
+ return { ok: false, error: `describe ${secretId}: ${r.stderr.trim()}` };
102
+ const replication = JSON.parse(r.stdout).replication;
103
+ if (replication?.automatic)
104
+ return { ok: true, replication: { kind: "automatic" } };
105
+ const locations = (replication?.userManaged?.replicas ?? [])
106
+ .map((r) => r.location)
107
+ .filter((l) => Boolean(l));
108
+ if (locations.length > 0) {
109
+ return { ok: true, replication: { kind: "user-managed", locations } };
110
+ }
111
+ return { ok: false, error: `${secretId} has no replication policy gcloud reports` };
112
+ }
113
+ function replicationArgs(replication) {
114
+ return replication.kind === "automatic"
115
+ ? ["--replication-policy=automatic"]
116
+ : ["--replication-policy=user-managed", `--locations=${replication.locations.join(",")}`];
117
+ }
118
+ /**
119
+ * Create each secret in `CLI_GENERATED_SECRETS` that is missing, and give
120
+ * one that exists without an enabled version a first version. A secret that
121
+ * already has an enabled version is never touched, so re-runs keep values.
122
+ *
123
+ * `seed` carries values a service already runs with as plain env vars (an
124
+ * operator-set `CAELO_INTERNAL_SECRET`): the new secret starts with that
125
+ * value, so moving the var to Secret Manager migrates the credential
126
+ * instead of silently rotating it under callers that sign with it.
127
+ */
128
+ export async function ensureGeneratedSecrets(install, deps = {}) {
129
+ const run = deps.run ?? defaultGcloud;
130
+ const sleep = deps.sleep ?? realSleep;
131
+ const generate = deps.generate ?? generateSecretValue;
132
+ const project = `--project=${install.projectId}`;
133
+ const outcomes = [];
134
+ for (const name of CLI_GENERATED_SECRETS) {
135
+ const secretId = gcpSecretId(install.env, name);
136
+ const id = `secret ${secretId}`;
137
+ const describe = await run(["secrets", "describe", secretId, project, "--format=value(name)"]);
138
+ if (!describe.ok && !NOT_FOUND.test(describe.stderr)) {
139
+ outcomes.push({ id, status: "failed", error: describe.stderr.trim() });
140
+ continue;
141
+ }
142
+ if (!describe.ok) {
143
+ const create = await run([
144
+ "secrets",
145
+ "create",
146
+ secretId,
147
+ project,
148
+ ...replicationArgs(install.replication),
149
+ "--data-file=-",
150
+ "--quiet",
151
+ ], { stdin: install.seed?.[name] || generate() });
152
+ if (create.ok) {
153
+ outcomes.push({ id, status: "applied" });
154
+ continue;
155
+ }
156
+ if (!ALREADY_EXISTS.test(create.stderr)) {
157
+ outcomes.push({ id, status: "failed", error: create.stderr.trim() });
158
+ continue;
159
+ }
160
+ // Created concurrently — fall through to the version check.
161
+ }
162
+ const versions = await runWithRetry(run, sleep, [
163
+ "secrets",
164
+ "versions",
165
+ "list",
166
+ secretId,
167
+ project,
168
+ "--filter=state:ENABLED",
169
+ "--limit=1",
170
+ "--format=value(name)",
171
+ ]);
172
+ if (!versions.ok) {
173
+ outcomes.push({ id, status: "failed", error: versions.stderr.trim() });
174
+ continue;
175
+ }
176
+ if (versions.stdout.trim()) {
177
+ outcomes.push({ id, status: "present" });
178
+ continue;
179
+ }
180
+ const add = await addVersion(run, secretId, project, install.seed?.[name] || generate());
181
+ outcomes.push(add.ok ? { id, status: "applied" } : { id, status: "failed", error: add.error });
182
+ }
183
+ return outcomes;
184
+ }
185
+ async function addVersion(run, secretId, project, value) {
186
+ const r = await run(["secrets", "versions", "add", secretId, project, "--data-file=-"], {
187
+ stdin: value,
188
+ });
189
+ return r.ok ? { ok: true } : { ok: false, error: r.stderr.trim() };
190
+ }
191
+ // ===========================================================================
192
+ // rotate-secret
193
+ // ===========================================================================
194
+ /** The secrets `rotate-secret` can rotate. */
195
+ export const ROTATABLE_SECRETS = [
196
+ "postgres-password",
197
+ "internal-secret",
198
+ "tool-approval-secret",
199
+ ];
200
+ /**
201
+ * Why `name` cannot be rotated, or `null` when it can.
202
+ *
203
+ * The KEK is refused: AI provider keys and other at-rest secrets in
204
+ * cms_admin are encrypted under it, and a new KEK without re-encrypting
205
+ * them would make them unreadable.
206
+ */
207
+ export function rotationRefusal(name) {
208
+ if (ROTATABLE_SECRETS.includes(name))
209
+ return null;
210
+ if (name === "secret-kek") {
211
+ return "secret-kek encrypts the AI provider keys and other at-rest secrets in cms_admin; a new KEK would make them unreadable. Rotating it needs a re-encryption step that does not exist yet.";
212
+ }
213
+ return `${name} is not a runtime secret of this install. Rotatable: ${ROTATABLE_SECRETS.join(", ")}.`;
214
+ }
215
+ /** The database roles that authenticate with `postgres-password`. */
216
+ const DATABASE_ROLES = ["admin_role", "public_role"];
217
+ /**
218
+ * The env vars each reader of `secret` must take from Secret Manager at
219
+ * `latest` for a new revision to pick up a rotated value. An install
220
+ * `upgrade` hasn't moved over still has the password inline in its URLs (a
221
+ * label-only roll would copy it unchanged), and a reference pinned to an
222
+ * older version would keep the old value — rotating either would report
223
+ * success and leave the services on a value the database no longer accepts.
224
+ */
225
+ async function checkRotationReaders(run, target, secret) {
226
+ const secretId = gcpSecretId(target.env, secret);
227
+ for (const service of ["admin", "gateway"]) {
228
+ const vars = Object.entries(SERVICE_SECRET_ENV[service])
229
+ .filter(([, s]) => s === secret)
230
+ .map(([name]) => name);
231
+ if (vars.length === 0)
232
+ continue;
233
+ const name = target.services[service];
234
+ const describe = await run([
235
+ "run",
236
+ "services",
237
+ "describe",
238
+ name,
239
+ "--region",
240
+ target.region,
241
+ `--project=${target.projectId}`,
242
+ "--format=json",
243
+ ]);
244
+ if (!describe.ok)
245
+ return `read the ${service} (${name}): ${describe.stderr.trim()}`;
246
+ const env = liveContainerEnv(describe.stdout);
247
+ const wrong = vars.filter((v) => {
248
+ const live = env.get(v);
249
+ return (live?.kind !== "secret" ||
250
+ !(live.secret === secretId || live.secret.endsWith(`/secrets/${secretId}`)) ||
251
+ live.version !== "latest");
252
+ });
253
+ if (wrong.length > 0) {
254
+ return `the ${service} (${name}) does not read ${wrong.join(", ")} from ${secretId} at latest, so a rotated value would not reach it. Run \`cms-provision upgrade\` first (it moves the services onto Secret Manager references), then rotate. Nothing was changed.`;
255
+ }
256
+ }
257
+ return null;
258
+ }
259
+ const SQL_ADMIN = "https://sqladmin.googleapis.com/v1";
260
+ const SQL_OPERATION_POLLS = 60;
261
+ /**
262
+ * Set a Cloud SQL user's password through the Cloud SQL Admin API, with the
263
+ * password in the request body. `gcloud sql users set-password` only takes
264
+ * it on argv (visible in process listings and exec logs) or from a tty
265
+ * prompt, so it is not used. The bearer token comes from the operator's
266
+ * gcloud session, like every other call here.
267
+ */
268
+ async function setSqlUserPassword(run, http, sleep, user) {
269
+ const token = await run(["auth", "print-access-token"]);
270
+ const bearer = token.ok ? token.stdout.trim() : "";
271
+ if (!bearer) {
272
+ return {
273
+ ok: false,
274
+ error: `gcloud auth print-access-token: ${token.stderr.trim() || "empty"}`,
275
+ };
276
+ }
277
+ const headers = { Authorization: `Bearer ${bearer}`, "Content-Type": "application/json" };
278
+ const project = `${SQL_ADMIN}/projects/${encodeURIComponent(user.projectId)}`;
279
+ const failed = async (what, res) => ({
280
+ ok: false,
281
+ error: `${what}: HTTP ${res.status} ${(await res.text()).slice(0, 500)}`,
282
+ });
283
+ const put = await http(`${project}/instances/${encodeURIComponent(user.instance)}/users?name=${encodeURIComponent(user.role)}`, { method: "PUT", headers, body: JSON.stringify({ name: user.role, password: user.password }) });
284
+ if (!put.ok)
285
+ return failed("update the user", put);
286
+ let op = JSON.parse(await put.text());
287
+ for (let i = 0; op.status !== "DONE" && i < SQL_OPERATION_POLLS; i++) {
288
+ if (!op.name)
289
+ return { ok: false, error: "the Cloud SQL API returned no operation name" };
290
+ await sleep(2_000);
291
+ const poll = await http(`${project}/operations/${encodeURIComponent(op.name)}`, {
292
+ method: "GET",
293
+ headers,
294
+ });
295
+ if (!poll.ok)
296
+ return failed(`poll operation ${op.name}`, poll);
297
+ op = JSON.parse(await poll.text());
298
+ }
299
+ if (op.status !== "DONE") {
300
+ return { ok: false, error: `operation ${op.name ?? "?"} did not finish in time` };
301
+ }
302
+ if (op.error) {
303
+ return {
304
+ ok: false,
305
+ error: (op.error.errors ?? []).map((e) => e.message ?? "?").join("; ") || "operation failed",
306
+ };
307
+ }
308
+ return { ok: true };
309
+ }
310
+ /** The two gcloud calls that roll `name` onto the `latest` version of its secrets. */
311
+ function rollArgs(name, region, projectId) {
312
+ const location = ["--region", region, `--project=${projectId}`];
313
+ return [
314
+ // A label change copies to the revision template, so it creates a new
315
+ // revision, which resolves `latest` again.
316
+ [
317
+ "run",
318
+ "services",
319
+ "update",
320
+ name,
321
+ ...location,
322
+ `--update-labels=caelo-secret-rotated=${Date.now()}`,
323
+ "--quiet",
324
+ ],
325
+ ["run", "services", "update-traffic", name, ...location, "--to-latest", "--quiet"],
326
+ ];
327
+ }
328
+ /**
329
+ * Rotate one runtime secret: store a new value as a new Secret Manager
330
+ * version and roll every service that reads it, so new revisions resolve
331
+ * `latest` to the new value.
332
+ *
333
+ * Nothing changes unless every reader takes the secret from Secret Manager
334
+ * at `latest` ({@link checkRotationReaders}).
335
+ *
336
+ * `postgres-password` also changes the password of both database roles,
337
+ * first, so the new version never holds a password the database rejects.
338
+ * The password goes to the Cloud SQL Admin API in a request body, never on
339
+ * argv. If a step before the new version is stored fails, the roles are
340
+ * set back to the previous value. Between the password change and the
341
+ * roll, instances of the old revision keep their open connections but
342
+ * cannot open new ones — the roll follows immediately, and it is attempted
343
+ * for every reader even when one fails, so one failed service never leaves
344
+ * the other behind. A failed roll is resumed with the printed commands
345
+ * (rolling again picks up the stored value; it does not rotate again).
346
+ */
347
+ export async function rotateRuntimeSecret(target, secret, deps = {}) {
348
+ const run = deps.run ?? defaultGcloud;
349
+ const sleep = deps.sleep ?? realSleep;
350
+ const http = deps.http ?? fetch;
351
+ const generate = deps.generate ?? generateSecretValue;
352
+ const project = `--project=${target.projectId}`;
353
+ const secretId = gcpSecretId(target.env, secret);
354
+ const steps = [];
355
+ const notReady = await checkRotationReaders(run, target, secret);
356
+ if (notReady)
357
+ return { ok: false, steps, error: notReady };
358
+ const value = generate();
359
+ if (secret === "postgres-password") {
360
+ if (!target.sqlInstance) {
361
+ return { ok: false, steps, error: "the Cloud SQL instance was not found" };
362
+ }
363
+ const instance = target.sqlInstance;
364
+ const current = await run([
365
+ "secrets",
366
+ "versions",
367
+ "access",
368
+ "latest",
369
+ `--secret=${secretId}`,
370
+ project,
371
+ ]);
372
+ if (!current.ok) {
373
+ return { ok: false, steps, error: `read the current password: ${current.stderr.trim()}` };
374
+ }
375
+ const previous = current.stdout;
376
+ const setPassword = (role, password) => setSqlUserPassword(run, http, sleep, {
377
+ projectId: target.projectId,
378
+ instance,
379
+ role,
380
+ password,
381
+ });
382
+ const changed = [];
383
+ const restore = async () => {
384
+ const failed = [];
385
+ for (const role of changed) {
386
+ if (!(await setPassword(role, previous)).ok)
387
+ failed.push(role);
388
+ }
389
+ return failed.length === 0
390
+ ? "the database roles were set back to the previous password"
391
+ : `could NOT set ${failed.join(", ")} back to the previous password — set it to the latest version of ${secretId} by hand`;
392
+ };
393
+ for (const role of DATABASE_ROLES) {
394
+ const r = await setPassword(role, value);
395
+ if (!r.ok) {
396
+ const restored = changed.length > 0 ? `; ${await restore()}` : "";
397
+ return {
398
+ ok: false,
399
+ steps,
400
+ error: `set the ${role} password: ${r.error}${restored}`,
401
+ };
402
+ }
403
+ changed.push(role);
404
+ steps.push(`set a new password on database role ${role}`);
405
+ }
406
+ const add = await addVersion(run, secretId, project, value);
407
+ if (!add.ok) {
408
+ return {
409
+ ok: false,
410
+ steps,
411
+ error: `store the new password in ${secretId}: ${add.error}; ${await restore()}`,
412
+ };
413
+ }
414
+ }
415
+ else {
416
+ const add = await addVersion(run, secretId, project, value);
417
+ if (!add.ok)
418
+ return { ok: false, steps, error: `add a version to ${secretId}: ${add.error}` };
419
+ }
420
+ steps.push(`added a new version to ${secretId}`);
421
+ const failures = [];
422
+ for (const service of ["admin", "gateway"]) {
423
+ if (!serviceSecrets(service).includes(secret))
424
+ continue;
425
+ const name = target.services[service];
426
+ const [update, flip] = rollArgs(name, target.region, target.projectId);
427
+ const rolled = await run(update);
428
+ const flipped = rolled.ok ? await run(flip) : rolled;
429
+ if (flipped.ok) {
430
+ steps.push(`rolled the ${service} onto the new value`);
431
+ continue;
432
+ }
433
+ failures.push(`roll the ${service} (${name}) onto the new value: ${flipped.stderr.trim()}\n resume with:\n gcloud ${update.join(" ")}\n gcloud ${flip.join(" ")}`);
434
+ }
435
+ if (failures.length > 0) {
436
+ return {
437
+ ok: false,
438
+ steps,
439
+ error: `The new value is stored${secret === "postgres-password" ? " and the database uses it" : ""}, but not every service runs on it yet. Do not rotate again — roll the remaining services onto it:\n${failures.join("\n")}`,
440
+ };
441
+ }
442
+ return { ok: true, steps };
443
+ }
444
+ //# sourceMappingURL=runtime-secrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-secrets.js","sourceRoot":"","sources":["../src/runtime-secrets.ts"],"names":[],"mappings":"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"}