@caelo-cms/provisioning 0.10.29 → 0.10.30

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 (82) 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 +65 -6
  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 +67 -0
  12. package/dist/deployed-release.d.ts.map +1 -0
  13. package/dist/deployed-release.js +144 -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.map +1 -1
  31. package/dist/lifecycle.js +314 -46
  32. package/dist/lifecycle.js.map +1 -1
  33. package/dist/mcp-iap.d.ts +5 -26
  34. package/dist/mcp-iap.d.ts.map +1 -1
  35. package/dist/mcp-iap.js +6 -18
  36. package/dist/mcp-iap.js.map +1 -1
  37. package/dist/migration-runner.d.ts +25 -0
  38. package/dist/migration-runner.d.ts.map +1 -1
  39. package/dist/migration-runner.js +60 -19
  40. package/dist/migration-runner.js.map +1 -1
  41. package/dist/operator-access.d.ts +83 -0
  42. package/dist/operator-access.d.ts.map +1 -0
  43. package/dist/operator-access.js +562 -0
  44. package/dist/operator-access.js.map +1 -0
  45. package/dist/runtime-secrets.d.ts +128 -0
  46. package/dist/runtime-secrets.d.ts.map +1 -0
  47. package/dist/runtime-secrets.js +444 -0
  48. package/dist/runtime-secrets.js.map +1 -0
  49. package/dist/stack-contract.d.ts +231 -0
  50. package/dist/stack-contract.d.ts.map +1 -0
  51. package/dist/stack-contract.js +455 -0
  52. package/dist/stack-contract.js.map +1 -0
  53. package/dist/stack-converge.d.ts +183 -0
  54. package/dist/stack-converge.d.ts.map +1 -0
  55. package/dist/stack-converge.js +513 -0
  56. package/dist/stack-converge.js.map +1 -0
  57. package/dist/wizard.d.ts.map +1 -1
  58. package/dist/wizard.js +8 -1
  59. package/dist/wizard.js.map +1 -1
  60. package/dist/wizards/gcp-cost.d.ts +6 -10
  61. package/dist/wizards/gcp-cost.d.ts.map +1 -1
  62. package/dist/wizards/gcp-cost.js +34 -2
  63. package/dist/wizards/gcp-cost.js.map +1 -1
  64. package/dist/wizards/gcp-pulumi.d.ts +32 -1
  65. package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
  66. package/dist/wizards/gcp-pulumi.js +60 -5
  67. package/dist/wizards/gcp-pulumi.js.map +1 -1
  68. package/dist/wizards/gcp.d.ts.map +1 -1
  69. package/dist/wizards/gcp.js +79 -16
  70. package/dist/wizards/gcp.js.map +1 -1
  71. package/package.json +3 -3
  72. package/stacks/aws/Pulumi.yaml +4 -0
  73. package/stacks/aws/index.ts +11 -0
  74. package/stacks/azure/Pulumi.yaml +4 -0
  75. package/stacks/azure/index.ts +10 -1
  76. package/stacks/gcp/Pulumi.yaml +4 -3
  77. package/stacks/gcp/README.md +13 -2
  78. package/stacks/gcp/index.ts +200 -140
  79. package/stacks/gcp-firebase/Pulumi.yaml +4 -0
  80. package/stacks/gcp-firebase/index.ts +165 -75
  81. package/stacks/self-hosted/Pulumi.yaml +4 -0
  82. package/stacks/self-hosted/index.ts +3 -0
@@ -0,0 +1,562 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * Set up (and converge) the operator-access sync job on a Google IAP install
4
+ * (`gcp`, `gcp-firebase`). Run by the wizard after migrations and by
5
+ * `cms-provision upgrade`, both as the operator's own gcloud identity.
6
+ *
7
+ * Trust boundary. Who may pass the admin's IAP gate and sign as `caelo-mcp`
8
+ * follows the Caelo user list. The admin does NOT write that: its runtime
9
+ * service account holds no IAM-policy rights. A Cloud Run job with its own
10
+ * service account (admin-core security/operator-access/sync-job.ts) is the
11
+ * only principal that may change those two bindings, and it only ever grants
12
+ * individual `user:` emails read from the database. The admin may only start
13
+ * the job (`roles/run.jobsExecutor` on that job: `run.jobs.run`, not
14
+ * `run.jobs.runWithOverrides`, so it cannot change the job's command, env or
15
+ * arguments — cloud.google.com/run/docs/reference/iam/roles) and read its
16
+ * runs (`roles/run.viewer` on the job). An admin compromise can add users to
17
+ * the database, but cannot make IAP public or grant any other role.
18
+ *
19
+ * What this ensures, every step idempotent:
20
+ * 1. the Cloud Scheduler API;
21
+ * 2. the custom role `caeloOperatorAccess` (get/setIamPolicy only);
22
+ * 3. the job's service account, bound to that role on exactly the admin's
23
+ * IAP resource and the `caelo-mcp` service account, plus
24
+ * `cloudsql.instanceUser` + `logging.logWriter`;
25
+ * 4. removal of the admin run SA's operator-access grants an earlier
26
+ * revision of this feature gave it;
27
+ * 5. Cloud SQL IAM database authentication (flag + the job's IAM database
28
+ * user, assigned the read-only `operator_access_reader` role that
29
+ * migration 0239 creates);
30
+ * 6. the job itself (admin image, its own SA, its env), the admin's
31
+ * execute/view grant on it, and an hourly Cloud Scheduler run.
32
+ *
33
+ * The CLI owns all of this rather than the stacks: the database user can only
34
+ * be given its role once migrations created the role, and a project custom
35
+ * role id is project-global, so a Pulumi-declared copy would collide with
36
+ * the one `upgrade` creates on older installs.
37
+ */
38
+ import { gcloud as defaultGcloud } from "./gcloud.js";
39
+ import { realSleep, runWithRetry } from "./gcloud-retry.js";
40
+ import { gcpNamePrefix, mcpIapServiceAccountEmail, operatorAccessJobName, operatorAccessScheduleName, operatorAccessServiceAccountEmail, operatorAccessServiceAccountId, runServiceAccountEmail, } from "./gcp-names.js";
41
+ import { iapResourceArgs } from "./mcp-iap.js";
42
+ /** The only IAM-writing rights in this feature, held by the sync job's SA alone. */
43
+ export const OPERATOR_ACCESS_ROLE = {
44
+ roleId: "caeloOperatorAccess",
45
+ title: "Caelo operator access",
46
+ description: "Lets the Caelo operator-access sync job set who passes the admin's IAP gate and who may sign as caelo-mcp. Bound only on those two resources, only to the job's service account.",
47
+ permissions: [
48
+ "iap.webServices.getIamPolicy",
49
+ "iap.webServices.setIamPolicy",
50
+ "iam.serviceAccounts.getIamPolicy",
51
+ "iam.serviceAccounts.setIamPolicy",
52
+ ],
53
+ };
54
+ /** Custom role an earlier revision bound to the admin run SA on `gcp`; its binding is removed. */
55
+ const LEGACY_LOOKUP_ROLE_ID = "caeloAdminIapLookup";
56
+ /** `projects/<project>/roles/<roleId>` — the name IAM bindings reference. */
57
+ export function customRoleName(projectId, roleId) {
58
+ return `projects/${projectId}/roles/${roleId}`;
59
+ }
60
+ /**
61
+ * The install's IAP allowlist: who passes IAP regardless of the user list.
62
+ * The wizard passes the same list to the stacks (`iapAllowlist`), and the
63
+ * job keeps these members instead of removing them, so `pulumi up` and the
64
+ * job never fight.
65
+ */
66
+ export function installIapAllowlist(ownerEmail) {
67
+ return [`user:${ownerEmail.trim().toLowerCase()}`];
68
+ }
69
+ /** Database role migration 0239 creates for the job. */
70
+ export const OPERATOR_ACCESS_DB_ROLE = "operator_access_reader";
71
+ /** Where the admin image ships the job's entry point. */
72
+ const SYNC_JOB_SCRIPT = "/app/packages/admin-core/src/security/operator-access/sync-job.ts";
73
+ /** The `iap_web` path of an IAP resource, as the IAP REST API names it. */
74
+ export function iapWebPath(resource) {
75
+ return resource.kind === "cloud-run"
76
+ ? `cloud_run-${resource.region}/services/${resource.service}`
77
+ : `compute/services/${resource.service}`;
78
+ }
79
+ /** Create the custom role, or bring an existing / soft-deleted one to spec. */
80
+ async function ensureCustomRole(run, projectId, role) {
81
+ const project = `--project=${projectId}`;
82
+ const permissions = `--permissions=${role.permissions.join(",")}`;
83
+ const describe = await run(["iam", "roles", "describe", role.roleId, project, "--format=json"]);
84
+ if (!describe.ok) {
85
+ const create = await run([
86
+ "iam",
87
+ "roles",
88
+ "create",
89
+ role.roleId,
90
+ project,
91
+ `--title=${role.title}`,
92
+ `--description=${role.description}`,
93
+ permissions,
94
+ "--stage=GA",
95
+ "--quiet",
96
+ ]);
97
+ return create.ok ? null : `create role ${role.roleId}: ${create.stderr.trim()}`;
98
+ }
99
+ const current = JSON.parse(describe.stdout);
100
+ if (current.deleted) {
101
+ const undelete = await run(["iam", "roles", "undelete", role.roleId, project, "--quiet"]);
102
+ if (!undelete.ok)
103
+ return `undelete role ${role.roleId}: ${undelete.stderr.trim()}`;
104
+ }
105
+ const have = [...(current.includedPermissions ?? [])].sort().join(",");
106
+ if (have === [...role.permissions].sort().join(","))
107
+ return null;
108
+ const update = await run([
109
+ "iam",
110
+ "roles",
111
+ "update",
112
+ role.roleId,
113
+ project,
114
+ permissions,
115
+ "--quiet",
116
+ ]);
117
+ return update.ok ? null : `update role ${role.roleId}: ${update.stderr.trim()}`;
118
+ }
119
+ /** Whether a gcloud IAM policy (JSON) grants `role` to `member` in any binding. */
120
+ function policyHas(policyJson, role, member) {
121
+ const policy = JSON.parse(policyJson.trim() || "{}");
122
+ return (policy.bindings ?? []).some((b) => b.role === role && (b.members ?? []).includes(member));
123
+ }
124
+ /** The flags of a Cloud SQL instance with `cloudsql.iam_authentication` on. */
125
+ export function withIamAuthFlag(flags) {
126
+ if (flags.some((f) => f.name === "cloudsql.iam_authentication" && f.value === "on"))
127
+ return null;
128
+ return [
129
+ ...flags.filter((f) => f.name !== "cloudsql.iam_authentication"),
130
+ { name: "cloudsql.iam_authentication", value: "on" },
131
+ ];
132
+ }
133
+ /** Ensure the operator-access sync job and everything it needs. Never throws for a gcloud failure. */
134
+ export async function ensureOperatorAccessSync(target, deps = {}) {
135
+ const run = deps.run ?? defaultGcloud;
136
+ const sleep = deps.sleep ?? realSleep;
137
+ const retry = (args) => runWithRetry(run, sleep, args);
138
+ const { projectId, region, env } = target;
139
+ const project = `--project=${projectId}`;
140
+ const jobSa = operatorAccessServiceAccountEmail(projectId, env);
141
+ const jobMember = `serviceAccount:${jobSa}`;
142
+ const runSaMember = `serviceAccount:${runServiceAccountEmail(projectId, env)}`;
143
+ const mcpSa = mcpIapServiceAccountEmail(projectId);
144
+ const customRole = customRoleName(projectId, OPERATOR_ACCESS_ROLE.roleId);
145
+ const jobName = operatorAccessJobName(env);
146
+ const done = [];
147
+ const fail = (step, r) => ({
148
+ ok: false,
149
+ done,
150
+ error: `${step}: ${r.stderr.trim()}`,
151
+ });
152
+ // 1. Cloud Scheduler API (the hourly self-healing run).
153
+ const api = await run([
154
+ "services",
155
+ "enable",
156
+ "cloudscheduler.googleapis.com",
157
+ project,
158
+ "--quiet",
159
+ ]);
160
+ if (!api.ok)
161
+ return fail("enable cloudscheduler.googleapis.com", api);
162
+ done.push("Cloud Scheduler API enabled");
163
+ // 2. The custom role.
164
+ const roleError = await ensureCustomRole(run, projectId, OPERATOR_ACCESS_ROLE);
165
+ if (roleError)
166
+ return { ok: false, done, error: roleError };
167
+ done.push(`custom role ${OPERATOR_ACCESS_ROLE.roleId}`);
168
+ // 3. The job's own service account and its grants.
169
+ const saDescribe = await run([
170
+ "iam",
171
+ "service-accounts",
172
+ "describe",
173
+ jobSa,
174
+ project,
175
+ "--format=value(email)",
176
+ ]);
177
+ if (!saDescribe.ok) {
178
+ const create = await run([
179
+ "iam",
180
+ "service-accounts",
181
+ "create",
182
+ operatorAccessServiceAccountId(env),
183
+ "--display-name=Caelo operator-access sync",
184
+ "--description=The only account that may change who passes the admin's IAP gate; runs the operator-access sync job.",
185
+ project,
186
+ ]);
187
+ if (!create.ok && !/already exists/i.test(create.stderr))
188
+ return fail(`create ${jobSa}`, create);
189
+ }
190
+ done.push(`service account ${jobSa}`);
191
+ const jobGrants = [
192
+ {
193
+ what: `${OPERATOR_ACCESS_ROLE.roleId} on the admin's IAP resource`,
194
+ args: ["iap", "web", "add-iam-policy-binding", ...iapResourceArgs(target.resource)],
195
+ },
196
+ {
197
+ what: `${OPERATOR_ACCESS_ROLE.roleId} on ${mcpSa}`,
198
+ args: ["iam", "service-accounts", "add-iam-policy-binding", mcpSa],
199
+ },
200
+ ];
201
+ for (const g of jobGrants) {
202
+ const r = await retry([
203
+ ...g.args,
204
+ `--member=${jobMember}`,
205
+ `--role=${customRole}`,
206
+ "--condition=None",
207
+ project,
208
+ "--quiet",
209
+ "--format=none",
210
+ ]);
211
+ if (!r.ok)
212
+ return fail(`grant the job ${g.what}`, r);
213
+ done.push(`job: ${g.what}`);
214
+ }
215
+ for (const role of ["roles/cloudsql.instanceUser", "roles/logging.logWriter"]) {
216
+ const r = await retry([
217
+ "projects",
218
+ "add-iam-policy-binding",
219
+ projectId,
220
+ `--member=${jobMember}`,
221
+ `--role=${role}`,
222
+ "--condition=None",
223
+ "--quiet",
224
+ "--format=none",
225
+ ]);
226
+ if (!r.ok)
227
+ return fail(`grant the job ${role}`, r);
228
+ done.push(`job: ${role} on the project`);
229
+ }
230
+ // 4. The admin's run SA loses every operator-access right an earlier
231
+ // revision gave it (it may only start the job now).
232
+ const legacy = [
233
+ {
234
+ what: "the admin's IAP resource",
235
+ get: [
236
+ "iap",
237
+ "web",
238
+ "get-iam-policy",
239
+ ...iapResourceArgs(target.resource),
240
+ project,
241
+ "--format=json",
242
+ ],
243
+ remove: ["iap", "web", "remove-iam-policy-binding", ...iapResourceArgs(target.resource)],
244
+ role: customRole,
245
+ },
246
+ {
247
+ what: mcpSa,
248
+ get: ["iam", "service-accounts", "get-iam-policy", mcpSa, project, "--format=json"],
249
+ remove: ["iam", "service-accounts", "remove-iam-policy-binding", mcpSa],
250
+ role: customRole,
251
+ },
252
+ {
253
+ what: "the project",
254
+ get: ["projects", "get-iam-policy", projectId, "--format=json"],
255
+ remove: ["projects", "remove-iam-policy-binding", projectId],
256
+ role: customRoleName(projectId, LEGACY_LOOKUP_ROLE_ID),
257
+ },
258
+ ];
259
+ for (const l of legacy) {
260
+ const policy = await run(l.get);
261
+ if (!policy.ok)
262
+ return fail(`read the IAM policy of ${l.what}`, policy);
263
+ if (!policyHas(policy.stdout, l.role, runSaMember))
264
+ continue;
265
+ const r = await retry([
266
+ ...l.remove,
267
+ `--member=${runSaMember}`,
268
+ `--role=${l.role}`,
269
+ "--all",
270
+ project,
271
+ "--quiet",
272
+ "--format=none",
273
+ ]);
274
+ if (!r.ok)
275
+ return fail(`remove the admin's ${l.role} on ${l.what}`, r);
276
+ done.push(`admin: removed ${l.role} on ${l.what}`);
277
+ }
278
+ // 5. Cloud SQL IAM database authentication for the job.
279
+ const instances = await run([
280
+ "sql",
281
+ "instances",
282
+ "list",
283
+ project,
284
+ `--filter=name~^${gcpNamePrefix(env)}-pg`,
285
+ "--format=value(name)",
286
+ ]);
287
+ if (!instances.ok)
288
+ return fail("list Cloud SQL instances", instances);
289
+ const names = instances.stdout
290
+ .split("\n")
291
+ .map((s) => s.trim())
292
+ .filter(Boolean);
293
+ if (names.length !== 1) {
294
+ return {
295
+ ok: false,
296
+ done,
297
+ error: `expected exactly one ${gcpNamePrefix(env)}-pg* Cloud SQL instance, found ${names.length} (${names.join(", ")})`,
298
+ };
299
+ }
300
+ const instance = names[0];
301
+ const flagsJson = await run([
302
+ "sql",
303
+ "instances",
304
+ "describe",
305
+ instance,
306
+ project,
307
+ "--format=json(settings.databaseFlags)",
308
+ ]);
309
+ if (!flagsJson.ok)
310
+ return fail(`read the flags of ${instance}`, flagsJson);
311
+ const flags = JSON.parse(flagsJson.stdout).settings?.databaseFlags ?? [];
312
+ const nextFlags = withIamAuthFlag(flags);
313
+ if (nextFlags) {
314
+ // `--database-flags` replaces the whole list, so every existing flag is
315
+ // passed again. cloudsql.iam_authentication needs no restart.
316
+ const patch = await run([
317
+ "sql",
318
+ "instances",
319
+ "patch",
320
+ instance,
321
+ project,
322
+ `--database-flags=${nextFlags.map((f) => `${f.name}=${f.value}`).join(",")}`,
323
+ "--quiet",
324
+ ]);
325
+ if (!patch.ok)
326
+ return fail(`enable IAM database authentication on ${instance}`, patch);
327
+ done.push(`${instance}: cloudsql.iam_authentication=on`);
328
+ }
329
+ const dbUser = jobSa.replace(/\.gserviceaccount\.com$/, "");
330
+ const users = await run([
331
+ "sql",
332
+ "users",
333
+ "list",
334
+ `--instance=${instance}`,
335
+ project,
336
+ "--format=value(name)",
337
+ ]);
338
+ if (!users.ok)
339
+ return fail(`list database users of ${instance}`, users);
340
+ if (!users.stdout
341
+ .split("\n")
342
+ .map((s) => s.trim())
343
+ .includes(dbUser)) {
344
+ const create = await run([
345
+ "sql",
346
+ "users",
347
+ "create",
348
+ dbUser,
349
+ `--instance=${instance}`,
350
+ "--type=cloud_iam_service_account",
351
+ project,
352
+ "--quiet",
353
+ ]);
354
+ if (!create.ok)
355
+ return fail(`create database user ${dbUser}`, create);
356
+ }
357
+ const assign = await run([
358
+ "sql",
359
+ "users",
360
+ "assign-roles",
361
+ dbUser,
362
+ `--instance=${instance}`,
363
+ "--type=cloud_iam_service_account",
364
+ `--database-roles=${OPERATOR_ACCESS_DB_ROLE}`,
365
+ project,
366
+ "--quiet",
367
+ ]);
368
+ if (!assign.ok)
369
+ return fail(`give ${dbUser} the ${OPERATOR_ACCESS_DB_ROLE} database role`, assign);
370
+ done.push(`database user ${dbUser} (${OPERATOR_ACCESS_DB_ROLE})`);
371
+ // 6. The job: the admin image with another entry point, the job's own SA,
372
+ // and its whole input as env the admin cannot override.
373
+ const envVars = [
374
+ `CAELO_OPERATOR_ACCESS_IAP_WEB=${iapWebPath(target.resource)}`,
375
+ `CAELO_MCP_IAP_SERVICE_ACCOUNT=${mcpSa}`,
376
+ `CAELO_OPERATOR_ACCESS_STATIC_MEMBERS=${installIapAllowlist(target.ownerEmail).join(",")}`,
377
+ `CAELO_OPERATOR_ACCESS_DB_HOST=${target.databaseHost}`,
378
+ ];
379
+ const deploy = await run([
380
+ "run",
381
+ "jobs",
382
+ "deploy",
383
+ jobName,
384
+ `--image=${target.imageRef}`,
385
+ `--region=${region}`,
386
+ project,
387
+ `--service-account=${jobSa}`,
388
+ `--network=${target.network}`,
389
+ `--subnet=${target.subnet}`,
390
+ "--vpc-egress=private-ranges-only",
391
+ "--command=bun",
392
+ `--args=--bun,${SYNC_JOB_SCRIPT}`,
393
+ // `^|^` switches gcloud's list delimiter: the static members contain commas.
394
+ `--set-env-vars=^|^${envVars.join("|")}`,
395
+ "--max-retries=1",
396
+ "--task-timeout=5m",
397
+ "--quiet",
398
+ ]);
399
+ if (!deploy.ok)
400
+ return fail(`deploy job ${jobName}`, deploy);
401
+ done.push(`job ${jobName}`);
402
+ const jobIam = [
403
+ {
404
+ member: runSaMember,
405
+ role: "roles/run.jobsExecutor",
406
+ why: "the admin starts the job (no overrides)",
407
+ },
408
+ { member: runSaMember, role: "roles/run.viewer", why: "the admin reads the job's runs" },
409
+ {
410
+ member: jobMember,
411
+ role: "roles/run.jobsExecutor",
412
+ why: "the hourly schedule starts the job as its own SA",
413
+ },
414
+ ];
415
+ for (const g of jobIam) {
416
+ const r = await retry([
417
+ "run",
418
+ "jobs",
419
+ "add-iam-policy-binding",
420
+ jobName,
421
+ `--region=${region}`,
422
+ project,
423
+ `--member=${g.member}`,
424
+ `--role=${g.role}`,
425
+ "--quiet",
426
+ "--format=none",
427
+ ]);
428
+ if (!r.ok)
429
+ return fail(`grant ${g.role} on ${jobName} (${g.why})`, r);
430
+ done.push(`${g.member}: ${g.role} on ${jobName}`);
431
+ }
432
+ const schedule = operatorAccessScheduleName(env);
433
+ const scheduleArgs = [
434
+ schedule,
435
+ `--location=${region}`,
436
+ project,
437
+ "--schedule=17 * * * *",
438
+ "--time-zone=Etc/UTC",
439
+ `--uri=https://run.googleapis.com/v2/projects/${projectId}/locations/${region}/jobs/${jobName}:run`,
440
+ "--http-method=POST",
441
+ `--oauth-service-account-email=${jobSa}`,
442
+ "--quiet",
443
+ ];
444
+ const existing = await run([
445
+ "scheduler",
446
+ "jobs",
447
+ "describe",
448
+ schedule,
449
+ `--location=${region}`,
450
+ project,
451
+ "--format=value(name)",
452
+ ]);
453
+ const sched = await retry([
454
+ "scheduler",
455
+ "jobs",
456
+ existing.ok ? "update" : "create",
457
+ "http",
458
+ ...scheduleArgs,
459
+ ]);
460
+ if (!sched.ok)
461
+ return fail(`schedule ${schedule}`, sched);
462
+ done.push(`hourly schedule ${schedule}`);
463
+ return { ok: true, done };
464
+ }
465
+ /**
466
+ * Everything {@link ensureOperatorAccessSync} needs, read from the deployed
467
+ * admin service: its network, the database host, and its IAP resource (the
468
+ * service itself on gcp-firebase, the LB backend service on gcp). `imageRef`
469
+ * overrides the image the job runs (upgrade passes the release it rolls to).
470
+ */
471
+ export async function resolveOperatorAccessTarget(opts, deps = {}) {
472
+ const run = deps.run ?? defaultGcloud;
473
+ const project = `--project=${opts.projectId}`;
474
+ const prefix = `${gcpNamePrefix(opts.env)}-admin`;
475
+ const list = await run([
476
+ "run",
477
+ "services",
478
+ "list",
479
+ `--region=${opts.region}`,
480
+ project,
481
+ `--filter=metadata.name~^${prefix}`,
482
+ "--format=value(metadata.name)",
483
+ ]);
484
+ if (!list.ok)
485
+ return { ok: false, error: `list Cloud Run services: ${list.stderr.trim()}` };
486
+ const services = lines(list.stdout);
487
+ if (services.length !== 1) {
488
+ return {
489
+ ok: false,
490
+ error: `expected exactly one ${prefix}* Cloud Run service, found ${services.length} (${services.join(", ")})`,
491
+ };
492
+ }
493
+ const adminService = services[0];
494
+ const describe = await run([
495
+ "run",
496
+ "services",
497
+ "describe",
498
+ adminService,
499
+ `--region=${opts.region}`,
500
+ project,
501
+ "--format=json",
502
+ ]);
503
+ if (!describe.ok) {
504
+ return { ok: false, error: `describe ${adminService}: ${describe.stderr.trim()}` };
505
+ }
506
+ const { parseAdminConfig } = await import("./migration-runner.js");
507
+ const admin = parseAdminConfig(describe.stdout);
508
+ if (!admin) {
509
+ return {
510
+ ok: false,
511
+ error: `${adminService} lacks an image, database host or VPC network the job can reuse`,
512
+ };
513
+ }
514
+ let resource;
515
+ if (opts.provider === "gcp-firebase") {
516
+ resource = { kind: "cloud-run", service: adminService, region: opts.region };
517
+ }
518
+ else {
519
+ const backends = await run([
520
+ "compute",
521
+ "backend-services",
522
+ "list",
523
+ "--global",
524
+ project,
525
+ `--filter=name~^${prefix}-backend AND iap.enabled=true`,
526
+ "--format=value(name)",
527
+ ]);
528
+ if (!backends.ok) {
529
+ return { ok: false, error: `list backend services: ${backends.stderr.trim()}` };
530
+ }
531
+ const names = lines(backends.stdout);
532
+ if (names.length !== 1) {
533
+ return {
534
+ ok: false,
535
+ error: `expected exactly one IAP-enabled ${prefix}-backend* backend service, found ${names.length} (${names.join(", ")})`,
536
+ };
537
+ }
538
+ resource = { kind: "backend-services", service: names[0] };
539
+ }
540
+ const short = (ref) => ref.split("/").pop() ?? ref;
541
+ return {
542
+ ok: true,
543
+ target: {
544
+ projectId: opts.projectId,
545
+ region: opts.region,
546
+ env: opts.env,
547
+ ownerEmail: opts.ownerEmail,
548
+ resource,
549
+ imageRef: opts.imageRef ?? admin.imageRef,
550
+ network: short(admin.networkRef),
551
+ subnet: short(admin.subnetRef),
552
+ databaseHost: admin.databaseHost,
553
+ },
554
+ };
555
+ }
556
+ function lines(stdout) {
557
+ return stdout
558
+ .split("\n")
559
+ .map((s) => s.trim())
560
+ .filter(Boolean);
561
+ }
562
+ //# sourceMappingURL=operator-access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operator-access.js","sourceRoot":"","sources":["../src/operator-access.ts"],"names":[],"mappings":"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"}