@caelo-cms/provisioning 0.10.44 → 0.10.46

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 (130) hide show
  1. package/dist/adc-impersonation.d.ts +28 -0
  2. package/dist/adc-impersonation.d.ts.map +1 -0
  3. package/dist/adc-impersonation.js +126 -0
  4. package/dist/adc-impersonation.js.map +1 -0
  5. package/dist/checkpoint-secrets.d.ts.map +1 -1
  6. package/dist/checkpoint-secrets.js +2 -1
  7. package/dist/checkpoint-secrets.js.map +1 -1
  8. package/dist/cli.js +199 -33
  9. package/dist/cli.js.map +1 -1
  10. package/dist/compose.d.ts +45 -0
  11. package/dist/compose.d.ts.map +1 -1
  12. package/dist/compose.js +112 -29
  13. package/dist/compose.js.map +1 -1
  14. package/dist/gcloud-retry.d.ts +5 -1
  15. package/dist/gcloud-retry.d.ts.map +1 -1
  16. package/dist/gcloud-retry.js.map +1 -1
  17. package/dist/gcloud.d.ts +2 -1
  18. package/dist/gcloud.d.ts.map +1 -1
  19. package/dist/gcloud.js +11 -13
  20. package/dist/gcloud.js.map +1 -1
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +3 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/infra-contract.d.ts +24 -0
  26. package/dist/infra-contract.d.ts.map +1 -0
  27. package/dist/infra-contract.js +25 -0
  28. package/dist/infra-contract.js.map +1 -0
  29. package/dist/install-state.d.ts +57 -2
  30. package/dist/install-state.d.ts.map +1 -1
  31. package/dist/install-state.js +142 -22
  32. package/dist/install-state.js.map +1 -1
  33. package/dist/lifecycle.d.ts +6 -0
  34. package/dist/lifecycle.d.ts.map +1 -1
  35. package/dist/lifecycle.js +185 -819
  36. package/dist/lifecycle.js.map +1 -1
  37. package/dist/migration-runner.d.ts +3 -0
  38. package/dist/migration-runner.d.ts.map +1 -1
  39. package/dist/migration-runner.js +7 -5
  40. package/dist/migration-runner.js.map +1 -1
  41. package/dist/ops-backend.d.ts +46 -0
  42. package/dist/ops-backend.d.ts.map +1 -0
  43. package/dist/ops-backend.js +370 -0
  44. package/dist/ops-backend.js.map +1 -0
  45. package/dist/provisioner-identity.d.ts +103 -0
  46. package/dist/provisioner-identity.d.ts.map +1 -0
  47. package/dist/provisioner-identity.js +323 -0
  48. package/dist/provisioner-identity.js.map +1 -0
  49. package/dist/regions.d.ts.map +1 -1
  50. package/dist/regions.js +2 -1
  51. package/dist/regions.js.map +1 -1
  52. package/dist/release-contract.d.ts +37 -0
  53. package/dist/release-contract.d.ts.map +1 -0
  54. package/dist/release-contract.js +55 -0
  55. package/dist/release-contract.js.map +1 -0
  56. package/dist/release-manifest.d.ts +140 -0
  57. package/dist/release-manifest.d.ts.map +1 -0
  58. package/dist/release-manifest.js +319 -0
  59. package/dist/release-manifest.js.map +1 -0
  60. package/dist/self-command.d.ts +16 -0
  61. package/dist/self-command.d.ts.map +1 -0
  62. package/dist/self-command.js +20 -0
  63. package/dist/self-command.js.map +1 -0
  64. package/dist/self-hosted-release.d.ts +81 -0
  65. package/dist/self-hosted-release.d.ts.map +1 -0
  66. package/dist/self-hosted-release.js +148 -0
  67. package/dist/self-hosted-release.js.map +1 -0
  68. package/dist/self-hosted-upgrade.d.ts +91 -0
  69. package/dist/self-hosted-upgrade.d.ts.map +1 -0
  70. package/dist/self-hosted-upgrade.js +355 -0
  71. package/dist/self-hosted-upgrade.js.map +1 -0
  72. package/dist/stack-converge.d.ts.map +1 -1
  73. package/dist/stack-converge.js +2 -1
  74. package/dist/stack-converge.js.map +1 -1
  75. package/dist/state-backend.d.ts +103 -0
  76. package/dist/state-backend.d.ts.map +1 -0
  77. package/dist/state-backend.js +180 -0
  78. package/dist/state-backend.js.map +1 -0
  79. package/dist/state-store.d.ts +55 -0
  80. package/dist/state-store.d.ts.map +1 -0
  81. package/dist/state-store.js +140 -0
  82. package/dist/state-store.js.map +1 -0
  83. package/dist/upgrade/app-roll.d.ts +164 -0
  84. package/dist/upgrade/app-roll.d.ts.map +1 -0
  85. package/dist/upgrade/app-roll.js +270 -0
  86. package/dist/upgrade/app-roll.js.map +1 -0
  87. package/dist/upgrade/backup.d.ts +48 -0
  88. package/dist/upgrade/backup.d.ts.map +1 -0
  89. package/dist/upgrade/backup.js +71 -0
  90. package/dist/upgrade/backup.js.map +1 -0
  91. package/dist/upgrade/converge.d.ts +45 -0
  92. package/dist/upgrade/converge.d.ts.map +1 -0
  93. package/dist/upgrade/converge.js +287 -0
  94. package/dist/upgrade/converge.js.map +1 -0
  95. package/dist/upgrade/gcp-lookup.d.ts +23 -0
  96. package/dist/upgrade/gcp-lookup.d.ts.map +1 -0
  97. package/dist/upgrade/gcp-lookup.js +95 -0
  98. package/dist/upgrade/gcp-lookup.js.map +1 -0
  99. package/dist/upgrade/health.d.ts +99 -0
  100. package/dist/upgrade/health.d.ts.map +1 -0
  101. package/dist/upgrade/health.js +214 -0
  102. package/dist/upgrade/health.js.map +1 -0
  103. package/dist/upgrade/release-images.d.ts +125 -0
  104. package/dist/upgrade/release-images.d.ts.map +1 -0
  105. package/dist/upgrade/release-images.js +315 -0
  106. package/dist/upgrade/release-images.js.map +1 -0
  107. package/dist/upgrade/reporter.d.ts +17 -0
  108. package/dist/upgrade/reporter.d.ts.map +1 -0
  109. package/dist/upgrade/reporter.js +28 -0
  110. package/dist/upgrade/reporter.js.map +1 -0
  111. package/dist/upgrade/upgrade.d.ts +79 -0
  112. package/dist/upgrade/upgrade.d.ts.map +1 -0
  113. package/dist/upgrade/upgrade.js +105 -0
  114. package/dist/upgrade/upgrade.js.map +1 -0
  115. package/dist/wizard.d.ts.map +1 -1
  116. package/dist/wizard.js +7 -3
  117. package/dist/wizard.js.map +1 -1
  118. package/dist/wizards/gcp-cost.d.ts.map +1 -1
  119. package/dist/wizards/gcp-cost.js +7 -1
  120. package/dist/wizards/gcp-cost.js.map +1 -1
  121. package/dist/wizards/gcp-pulumi.d.ts +99 -8
  122. package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
  123. package/dist/wizards/gcp-pulumi.js +157 -50
  124. package/dist/wizards/gcp-pulumi.js.map +1 -1
  125. package/dist/wizards/gcp.d.ts.map +1 -1
  126. package/dist/wizards/gcp.js +182 -58
  127. package/dist/wizards/gcp.js.map +1 -1
  128. package/package.json +4 -3
  129. package/stacks/self-hosted/README.md +4 -0
  130. package/stacks/self-hosted/index.ts +10 -2
@@ -0,0 +1,370 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * The install's ops bucket + Pulumi state key in its own GCP project (#696,
4
+ * D2). Ensured by the GCP wizard for every new install (before the cost
5
+ * confirmation — both are near-free, see gcp-cost.ts) and by
6
+ * the state migration for an existing one.
7
+ *
8
+ * - `gs://<project>-caelo-ops`, in the install region: object versioning
9
+ * on (every Pulumi checkpoint write is recoverable), uniform bucket-level
10
+ * access (no per-object ACLs), public access prevention enforced, and a
11
+ * lifecycle rule that deletes non-current versions after
12
+ * {@link NONCURRENT_VERSION_DAYS} days — Pulumi rewrites its checkpoint on
13
+ * every resource step, so unbounded versions would grow without end.
14
+ * - Cloud KMS key ring `caelo`, key `pulumi-state` (symmetric, software
15
+ * protection, no automatic rotation: each rotation adds a billed key
16
+ * version, and the key only wraps Pulumi's data key).
17
+ * - IAM: the operator and `caelo-provisioner` get object access on the
18
+ * bucket and encrypt/decrypt on the key — nobody else is granted
19
+ * anything. The bucket's convenience bindings for project viewers and
20
+ * editors are removed; public principals are refused outright. Project
21
+ * Owners keep access through their project role (that cannot be taken
22
+ * away at the bucket); docs-site/pages/install-gcp.md says so.
23
+ *
24
+ * Every step reads before it writes, so a re-run is a no-op and an operator
25
+ * without IAM-write permission can still run against an ops backend someone
26
+ * else ensured. Nothing here ever deletes a bucket, an object or a key.
27
+ */
28
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
29
+ import { tmpdir } from "node:os";
30
+ import { join } from "node:path";
31
+ import { gcloud as defaultGcloud } from "./gcloud.js";
32
+ import { realSleep, runWithRetry } from "./gcloud-retry.js";
33
+ import { operatorMember } from "./provisioner-identity.js";
34
+ import { gcsBackendRecord, OPS_KEY_RING, OPS_STATE_KEY, opsBucketName, } from "./state-backend.js";
35
+ /** Days a superseded Pulumi checkpoint version stays recoverable. */
36
+ export const NONCURRENT_VERSION_DAYS = 30;
37
+ /** Role the operator + provisioner hold on the ops bucket. */
38
+ export const OPS_BUCKET_ROLE = "roles/storage.objectAdmin";
39
+ /** Role the operator + provisioner hold on the state key. */
40
+ export const OPS_KEY_ROLE = "roles/cloudkms.cryptoKeyEncrypterDecrypter";
41
+ /** APIs the ops backend needs. */
42
+ const OPS_APIS = ["storage.googleapis.com", "cloudkms.googleapis.com"];
43
+ /** Principals that must never appear on the ops bucket. */
44
+ const PUBLIC_MEMBERS = new Set(["allUsers", "allAuthenticatedUsers"]);
45
+ /** gcloud's wording for a resource that does not exist (yet). */
46
+ const NOT_FOUND = /NOT_FOUND|NotFound|not found|404|does not exist/i;
47
+ function parseJson(text, fallback) {
48
+ try {
49
+ return JSON.parse(text || "null") ?? fallback;
50
+ }
51
+ catch {
52
+ return fallback;
53
+ }
54
+ }
55
+ /** The lifecycle rule the ops bucket carries — and no other. */
56
+ const OPS_LIFECYCLE_RULE = {
57
+ action: { type: "Delete" },
58
+ condition: { daysSinceNoncurrentTime: NONCURRENT_VERSION_DAYS, isLive: false },
59
+ };
60
+ /**
61
+ * Whether a bucket's lifecycle is exactly {@link OPS_LIFECYCLE_RULE}. Any
62
+ * other rule — a shorter window, a prefix filter, a rule deleting live
63
+ * objects — could cut the recovery window or delete the state itself, so
64
+ * it is replaced, not tolerated.
65
+ */
66
+ export function isOpsLifecycle(config) {
67
+ const rules = config?.rule;
68
+ if (!Array.isArray(rules) || rules.length !== 1)
69
+ return false;
70
+ const r = rules[0];
71
+ const cond = r.condition ?? {};
72
+ return (r.action?.type === "Delete" &&
73
+ Object.keys(r.action).length === 1 &&
74
+ cond.daysSinceNoncurrentTime === NONCURRENT_VERSION_DAYS &&
75
+ cond.isLive === false &&
76
+ Object.keys(cond).length === 2);
77
+ }
78
+ const hasBinding = (policy, role, member) => (policy.bindings ?? []).some((b) => b.role === role &&
79
+ b.condition == null &&
80
+ (b.members ?? []).some((m) => m.toLowerCase() === member.toLowerCase()));
81
+ const reason = (stderr, exitCode) => stderr.trim().split("\n").slice(-3).join(" ") || `gcloud exited ${exitCode}`;
82
+ /**
83
+ * Ensure the ops bucket + state key exist with the settings and IAM above.
84
+ * Idempotent; never throws for a gcloud failure (the result says what
85
+ * failed and what to run). With `dryRun` it only reads and reports what it
86
+ * would change.
87
+ */
88
+ export async function ensureOpsBackend(target, deps = {}) {
89
+ const run = deps.run ?? defaultGcloud;
90
+ const sleep = deps.sleep ?? realSleep;
91
+ const dryRun = deps.dryRun ?? false;
92
+ const { projectId, region } = target;
93
+ const project = `--project=${projectId}`;
94
+ const bucket = opsBucketName(projectId);
95
+ const bucketUrl = `gs://${bucket}`;
96
+ const members = [
97
+ operatorMember(target.operatorAccount),
98
+ `serviceAccount:${target.provisionerEmail}`,
99
+ ];
100
+ const actions = [];
101
+ const act = (what) => actions.push(dryRun ? `would ${what}` : what);
102
+ const fail = (what, r) => ({
103
+ ok: false,
104
+ error: `${what} failed: ${reason(r.stderr, r.exitCode)}`,
105
+ });
106
+ // --- APIs -------------------------------------------------------------
107
+ // Read first: an operator without serviceusage.services.enable can still
108
+ // re-run an install whose APIs are on.
109
+ const enabled = await run([
110
+ "services",
111
+ "list",
112
+ "--enabled",
113
+ project,
114
+ "--format=value(config.name)",
115
+ ]);
116
+ if (!enabled.ok)
117
+ return fail(`Listing the enabled APIs of ${projectId}`, enabled);
118
+ const on = new Set(enabled.stdout.split("\n").map((l) => l.trim()));
119
+ const missingApis = OPS_APIS.filter((a) => !on.has(a));
120
+ if (missingApis.length > 0) {
121
+ act(`enable ${missingApis.join(", ")}`);
122
+ if (!dryRun) {
123
+ const apis = await run(["services", "enable", ...missingApis, project]);
124
+ if (!apis.ok)
125
+ return fail(`Enabling ${missingApis.join(", ")}`, apis);
126
+ }
127
+ }
128
+ // --- Bucket -----------------------------------------------------------
129
+ const described = await run([
130
+ "storage",
131
+ "buckets",
132
+ "describe",
133
+ bucketUrl,
134
+ project,
135
+ "--format=json",
136
+ ]);
137
+ let bucketExists = described.ok;
138
+ if (!described.ok && !NOT_FOUND.test(described.stderr)) {
139
+ return {
140
+ ok: false,
141
+ error: `Could not read ${bucketUrl}: ${reason(described.stderr, described.exitCode)}. If the name is taken by a bucket outside project ${projectId}, the install can't use it — tell the maintainers (the name is <project>-caelo-ops).`,
142
+ };
143
+ }
144
+ if (bucketExists) {
145
+ // Bucket names are global and `--project` does not scope `describe`: a
146
+ // bucket of that name in a project the operator can also reach would
147
+ // otherwise receive this install's state.
148
+ const owned = await run(["storage", "buckets", "list", project, "--format=value(name)"]);
149
+ if (!owned.ok)
150
+ return fail(`Listing the buckets of project ${projectId}`, owned);
151
+ const names = owned.stdout.split("\n").map((l) => l
152
+ .trim()
153
+ .replace(/^gs:\/\//, "")
154
+ .replace(/\/$/, ""));
155
+ if (!names.includes(bucket)) {
156
+ return {
157
+ ok: false,
158
+ error: `${bucketUrl} exists but does not belong to project ${projectId}. The install's state must live in its own project; delete or rename that bucket, or tell the maintainers (the name is <project>-caelo-ops).`,
159
+ };
160
+ }
161
+ }
162
+ if (!bucketExists) {
163
+ act(`create ${bucketUrl} in ${region}`);
164
+ if (!dryRun) {
165
+ const created = await run([
166
+ "storage",
167
+ "buckets",
168
+ "create",
169
+ bucketUrl,
170
+ project,
171
+ `--location=${region}`,
172
+ "--default-storage-class=STANDARD",
173
+ "--uniform-bucket-level-access",
174
+ "--public-access-prevention",
175
+ ]);
176
+ if (!created.ok)
177
+ return fail(`Creating ${bucketUrl}`, created);
178
+ bucketExists = true;
179
+ }
180
+ }
181
+ const desc = described.ok ? parseJson(described.stdout, {}) : {};
182
+ // A bucket created above already has uniform access + public access
183
+ // prevention; `buckets create` has no versioning flag.
184
+ const updates = [];
185
+ if (desc.versioning_enabled !== true)
186
+ updates.push("--versioning");
187
+ if (described.ok && desc.uniform_bucket_level_access !== true) {
188
+ updates.push("--uniform-bucket-level-access");
189
+ }
190
+ if (described.ok && desc.public_access_prevention !== "enforced") {
191
+ updates.push("--public-access-prevention");
192
+ }
193
+ const hasLifecycle = isOpsLifecycle(desc.lifecycle_config);
194
+ if (updates.length > 0) {
195
+ act(`set ${updates.map((u) => u.slice(2)).join(", ")} on ${bucketUrl}`);
196
+ if (!dryRun) {
197
+ const r = await run(["storage", "buckets", "update", bucketUrl, project, ...updates]);
198
+ if (!r.ok)
199
+ return fail(`Updating ${bucketUrl}`, r);
200
+ }
201
+ }
202
+ if (!hasLifecycle) {
203
+ act(`set the lifecycle of ${bucketUrl} to: delete non-current object versions after ${NONCURRENT_VERSION_DAYS} days (nothing else)`);
204
+ if (!dryRun) {
205
+ // A private directory (mkdtemp, mode 700): no other local user can
206
+ // swap the file between write and read.
207
+ const dir = mkdtempSync(join(tmpdir(), "caelo-ops-"));
208
+ const file = join(dir, "lifecycle.json");
209
+ try {
210
+ writeFileSync(file, JSON.stringify({ rule: [OPS_LIFECYCLE_RULE] }), { mode: 0o600 });
211
+ const r = await run([
212
+ "storage",
213
+ "buckets",
214
+ "update",
215
+ bucketUrl,
216
+ project,
217
+ `--lifecycle-file=${file}`,
218
+ ]);
219
+ if (!r.ok)
220
+ return fail(`Setting the lifecycle rule on ${bucketUrl}`, r);
221
+ }
222
+ finally {
223
+ rmSync(dir, { recursive: true, force: true });
224
+ }
225
+ }
226
+ }
227
+ // --- Bucket IAM -------------------------------------------------------
228
+ if (bucketExists) {
229
+ const got = await run([
230
+ "storage",
231
+ "buckets",
232
+ "get-iam-policy",
233
+ bucketUrl,
234
+ project,
235
+ "--format=json",
236
+ ]);
237
+ if (!got.ok)
238
+ return fail(`Reading the IAM policy of ${bucketUrl}`, got);
239
+ const policy = parseJson(got.stdout, {});
240
+ const exposed = (policy.bindings ?? []).flatMap((b) => (b.members ?? []).filter((m) => PUBLIC_MEMBERS.has(m)).map((m) => `${m} (${b.role})`));
241
+ if (exposed.length > 0) {
242
+ return {
243
+ ok: false,
244
+ error: `${bucketUrl} grants ${exposed.join(", ")}. It holds the install's infrastructure state and must never be public. Remove those bindings (gcloud storage buckets remove-iam-policy-binding ${bucketUrl} --member=<member> --role=<role>) and re-run.`,
245
+ };
246
+ }
247
+ for (const member of members) {
248
+ if (hasBinding(policy, OPS_BUCKET_ROLE, member))
249
+ continue;
250
+ act(`grant ${member} ${OPS_BUCKET_ROLE} on ${bucketUrl}`);
251
+ if (dryRun)
252
+ continue;
253
+ const r = await runWithRetry(run, sleep, [
254
+ "storage",
255
+ "buckets",
256
+ "add-iam-policy-binding",
257
+ bucketUrl,
258
+ project,
259
+ `--member=${member}`,
260
+ `--role=${OPS_BUCKET_ROLE}`,
261
+ ]);
262
+ if (!r.ok)
263
+ return fail(`Granting ${member} access to ${bucketUrl}`, r);
264
+ }
265
+ for (const b of policy.bindings ?? []) {
266
+ for (const m of b.members ?? []) {
267
+ if (!/^project(Viewer|Editor):/.test(m) || !b.role)
268
+ continue;
269
+ act(`remove ${m} ${b.role} from ${bucketUrl}`);
270
+ if (dryRun)
271
+ continue;
272
+ const r = await run([
273
+ "storage",
274
+ "buckets",
275
+ "remove-iam-policy-binding",
276
+ bucketUrl,
277
+ project,
278
+ `--member=${m}`,
279
+ `--role=${b.role}`,
280
+ ]);
281
+ if (!r.ok)
282
+ return fail(`Removing ${m} from ${bucketUrl}`, r);
283
+ }
284
+ }
285
+ }
286
+ else {
287
+ for (const member of members)
288
+ act(`grant ${member} ${OPS_BUCKET_ROLE} on ${bucketUrl}`);
289
+ }
290
+ // --- KMS key ring + key -------------------------------------------------
291
+ const kmsWhere = [`--location=${region}`, project];
292
+ const ring = await run([
293
+ "kms",
294
+ "keyrings",
295
+ "describe",
296
+ OPS_KEY_RING,
297
+ ...kmsWhere,
298
+ "--format=value(name)",
299
+ ]);
300
+ // In a dry run the KMS API may still be disabled; that reads as "not there yet".
301
+ const ringMissing = !ring.ok && (NOT_FOUND.test(ring.stderr) || dryRun);
302
+ if (!ring.ok && !ringMissing)
303
+ return fail(`Reading key ring ${OPS_KEY_RING}`, ring);
304
+ if (ringMissing) {
305
+ act(`create KMS key ring ${OPS_KEY_RING} in ${region}`);
306
+ if (!dryRun) {
307
+ const r = await run(["kms", "keyrings", "create", OPS_KEY_RING, ...kmsWhere]);
308
+ if (!r.ok)
309
+ return fail(`Creating key ring ${OPS_KEY_RING}`, r);
310
+ }
311
+ }
312
+ const keyWhere = [`--keyring=${OPS_KEY_RING}`, ...kmsWhere];
313
+ const key = ringMissing
314
+ ? { ok: false, stderr: "NOT_FOUND", stdout: "", exitCode: 1 }
315
+ : await run(["kms", "keys", "describe", OPS_STATE_KEY, ...keyWhere, "--format=value(name)"]);
316
+ const keyMissing = !key.ok && NOT_FOUND.test(key.stderr);
317
+ if (!key.ok && !keyMissing)
318
+ return fail(`Reading key ${OPS_STATE_KEY}`, key);
319
+ if (keyMissing) {
320
+ act(`create KMS key ${OPS_KEY_RING}/${OPS_STATE_KEY}`);
321
+ if (!dryRun) {
322
+ const r = await run([
323
+ "kms",
324
+ "keys",
325
+ "create",
326
+ OPS_STATE_KEY,
327
+ ...keyWhere,
328
+ "--purpose=encryption",
329
+ "--protection-level=software",
330
+ ]);
331
+ if (!r.ok)
332
+ return fail(`Creating key ${OPS_STATE_KEY}`, r);
333
+ }
334
+ }
335
+ // --- Key IAM ------------------------------------------------------------
336
+ let keyPolicy = {};
337
+ if (!keyMissing) {
338
+ const got = await run([
339
+ "kms",
340
+ "keys",
341
+ "get-iam-policy",
342
+ OPS_STATE_KEY,
343
+ ...keyWhere,
344
+ "--format=json",
345
+ ]);
346
+ if (!got.ok)
347
+ return fail(`Reading the IAM policy of key ${OPS_STATE_KEY}`, got);
348
+ keyPolicy = parseJson(got.stdout, {});
349
+ }
350
+ for (const member of members) {
351
+ if (hasBinding(keyPolicy, OPS_KEY_ROLE, member))
352
+ continue;
353
+ act(`grant ${member} ${OPS_KEY_ROLE} on ${OPS_KEY_RING}/${OPS_STATE_KEY}`);
354
+ if (dryRun)
355
+ continue;
356
+ const r = await runWithRetry(run, sleep, [
357
+ "kms",
358
+ "keys",
359
+ "add-iam-policy-binding",
360
+ OPS_STATE_KEY,
361
+ ...keyWhere,
362
+ `--member=${member}`,
363
+ `--role=${OPS_KEY_ROLE}`,
364
+ ]);
365
+ if (!r.ok)
366
+ return fail(`Granting ${member} use of key ${OPS_STATE_KEY}`, r);
367
+ }
368
+ return { ok: true, record: gcsBackendRecord(projectId, region), actions };
369
+ }
370
+ //# sourceMappingURL=ops-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ops-backend.js","sourceRoot":"","sources":["../src/ops-backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ import { type GcloudRunner, type Sleep } from "./gcloud-retry.js";
2
+ /** Account id of the service account Pulumi converges the stack as. */
3
+ export declare const PROVISIONER_ACCOUNT_ID = "caelo-provisioner";
4
+ /** The role that lets the operator impersonate the provisioner. */
5
+ export declare const TOKEN_CREATOR_ROLE = "roles/iam.serviceAccountTokenCreator";
6
+ /** File name of the JSON key installers before #696 kept in `secrets/`. */
7
+ export declare const LEGACY_SA_KEY_FILE = "sa-key.json";
8
+ /**
9
+ * Environment variables that would make Google's client libraries use a
10
+ * credential other than the operator's Application Default Credentials —
11
+ * a key file (perhaps the deleted `sa-key.json`), a static token that expires
12
+ * after an hour, or another impersonation target. Removed from every
13
+ * infrastructure run so the chain is always ADC → impersonated provisioner.
14
+ */
15
+ export declare const AMBIENT_GOOGLE_CREDENTIAL_ENV: readonly string[];
16
+ /** `caelo-provisioner@<project>.iam.gserviceaccount.com`. */
17
+ export declare function provisionerServiceAccountEmail(projectId: string): string;
18
+ /** `base` without the credential variables {@link AMBIENT_GOOGLE_CREDENTIAL_ENV} lists. */
19
+ export declare function withoutAmbientGoogleCredentials(base: NodeJS.ProcessEnv): Record<string, string>;
20
+ /** IAM member for a gcloud account: a service account when it is one, else a user. */
21
+ export declare function operatorMember(account: string): string;
22
+ export type ImpersonationGrant = {
23
+ readonly ok: true;
24
+ readonly status: "already" | "granted";
25
+ } | {
26
+ readonly ok: false;
27
+ readonly error: string;
28
+ };
29
+ /**
30
+ * Give the operator's gcloud account `roles/iam.serviceAccountTokenCreator`
31
+ * on the provisioner service account (and on nothing else). Reads the
32
+ * account's IAM policy first, so an operator who was granted the role by
33
+ * someone else needs no IAM-write permission. Never throws for a gcloud
34
+ * failure.
35
+ */
36
+ export declare function ensureProvisionerImpersonation(target: {
37
+ readonly projectId: string;
38
+ readonly operatorAccount: string;
39
+ }, deps?: {
40
+ run?: GcloudRunner;
41
+ sleep?: Sleep;
42
+ }): Promise<ImpersonationGrant>;
43
+ export type LegacyKeyReport = {
44
+ readonly ok: true;
45
+ /** `none`: no local key file. `removed`: file (and its IAM key, if live) deleted. */
46
+ readonly status: "none" | "removed";
47
+ /** The IAM key id deleted, when the key was still live in IAM. */
48
+ readonly deletedKeyId?: string;
49
+ /** Lines for the operator: what was removed, other keys found. */
50
+ readonly lines: string[];
51
+ } | {
52
+ readonly ok: false;
53
+ readonly error: string;
54
+ };
55
+ /**
56
+ * Delete the provisioner's JSON key an installer before #696 minted: first
57
+ * the IAM key whose id matches the local file's `private_key_id`, then the
58
+ * file. The file is only removed once its key is gone from IAM, so a failed
59
+ * IAM delete can be retried on the next run. Other user-managed keys of the
60
+ * account are listed in `lines` with the command to delete them — never
61
+ * deleted here. Idempotent: no local file means nothing to do. Never throws
62
+ * for a gcloud failure.
63
+ */
64
+ export declare function removeLegacyProvisionerKey(target: {
65
+ readonly projectId: string;
66
+ readonly secretsDir: string;
67
+ }, deps?: {
68
+ run?: GcloudRunner;
69
+ }): Promise<LegacyKeyReport>;
70
+ /** Delays between impersonation probes while a fresh TokenCreator grant propagates. */
71
+ export declare const PROPAGATION_DELAYS_MS: readonly number[];
72
+ export type KeylessConvergence = {
73
+ readonly ok: true;
74
+ /** `no-provisioner`: the project has no caelo-provisioner account; nothing to do. */
75
+ readonly grant: "already" | "granted" | "no-provisioner";
76
+ readonly legacyKey: "none" | "removed";
77
+ readonly lines: string[];
78
+ } | {
79
+ readonly ok: false;
80
+ readonly error: string;
81
+ };
82
+ /**
83
+ * Bring an install to the keyless provisioner (#696): the operator's gcloud
84
+ * account may impersonate `caelo-provisioner`, and a key an older installer
85
+ * minted is gone, locally and in IAM. The grant comes first, so a run that
86
+ * cannot set it up stops before the key — today's only working credential
87
+ * for older tooling — is deleted. Shared by the installer and `upgrade`;
88
+ * idempotent; never throws for a gcloud failure.
89
+ */
90
+ export declare function convergeKeylessProvisioner(target: {
91
+ readonly projectId: string;
92
+ readonly secretsDir: string;
93
+ readonly operatorAccount: string;
94
+ /**
95
+ * The installer just created the account: wait out IAM's propagation
96
+ * delay instead of reading a NOT_FOUND as "no provisioner".
97
+ */
98
+ readonly justCreated?: boolean;
99
+ }, deps?: {
100
+ run?: GcloudRunner;
101
+ sleep?: Sleep;
102
+ }): Promise<KeylessConvergence>;
103
+ //# sourceMappingURL=provisioner-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisioner-identity.d.ts","sourceRoot":"","sources":["../src/provisioner-identity.ts"],"names":[],"mappings":"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"}