@caelo-cms/provisioning 0.10.55 → 0.10.58

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 (221) hide show
  1. package/dist/agent-db.js +97 -24
  2. package/dist/cli-routing.js +1 -1
  3. package/dist/cli-routing.js.map +1 -1
  4. package/dist/cli.js +4 -1
  5. package/dist/cli.js.map +1 -1
  6. package/dist/compose.js +5 -0
  7. package/dist/compose.js.map +1 -1
  8. package/dist/converge-checkpoint.d.ts +66 -0
  9. package/dist/converge-checkpoint.d.ts.map +1 -0
  10. package/dist/converge-checkpoint.js +61 -0
  11. package/dist/converge-checkpoint.js.map +1 -0
  12. package/dist/converge-job-gcp.d.ts +46 -0
  13. package/dist/converge-job-gcp.d.ts.map +1 -0
  14. package/dist/converge-job-gcp.js +368 -0
  15. package/dist/converge-job-gcp.js.map +1 -0
  16. package/dist/converge-job-setup.d.ts +62 -0
  17. package/dist/converge-job-setup.d.ts.map +1 -0
  18. package/dist/converge-job-setup.js +228 -0
  19. package/dist/converge-job-setup.js.map +1 -0
  20. package/dist/converge-job.d.ts +141 -0
  21. package/dist/converge-job.d.ts.map +1 -0
  22. package/dist/converge-job.js +325 -0
  23. package/dist/converge-job.js.map +1 -0
  24. package/dist/gcp-names.d.ts +9 -0
  25. package/dist/gcp-names.d.ts.map +1 -1
  26. package/dist/gcp-names.js +13 -0
  27. package/dist/gcp-names.js.map +1 -1
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +2 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/infra-contract.d.ts +1 -1
  33. package/dist/infra-contract.d.ts.map +1 -1
  34. package/dist/infra-contract.js +33 -1
  35. package/dist/infra-contract.js.map +1 -1
  36. package/dist/install-job.d.ts +11 -3
  37. package/dist/install-job.d.ts.map +1 -1
  38. package/dist/install-job.js +22 -12
  39. package/dist/install-job.js.map +1 -1
  40. package/dist/lifecycle.d.ts +13 -1
  41. package/dist/lifecycle.d.ts.map +1 -1
  42. package/dist/lifecycle.js +115 -58
  43. package/dist/lifecycle.js.map +1 -1
  44. package/dist/operator-access.d.ts +4 -0
  45. package/dist/operator-access.d.ts.map +1 -1
  46. package/dist/operator-access.js +43 -7
  47. package/dist/operator-access.js.map +1 -1
  48. package/dist/release-contract.d.ts +3 -2
  49. package/dist/release-contract.d.ts.map +1 -1
  50. package/dist/release-contract.js +5 -2
  51. package/dist/release-contract.js.map +1 -1
  52. package/dist/release-manifest.d.ts +2 -0
  53. package/dist/release-manifest.d.ts.map +1 -1
  54. package/dist/release-manifest.js.map +1 -1
  55. package/dist/remote-mcp-edge.d.ts +114 -0
  56. package/dist/remote-mcp-edge.d.ts.map +1 -0
  57. package/dist/remote-mcp-edge.js +116 -0
  58. package/dist/remote-mcp-edge.js.map +1 -0
  59. package/dist/remote-mcp.d.ts +139 -0
  60. package/dist/remote-mcp.d.ts.map +1 -0
  61. package/dist/remote-mcp.js +434 -0
  62. package/dist/remote-mcp.js.map +1 -0
  63. package/dist/runtime-secrets.d.ts +12 -0
  64. package/dist/runtime-secrets.d.ts.map +1 -1
  65. package/dist/runtime-secrets.js +32 -4
  66. package/dist/runtime-secrets.js.map +1 -1
  67. package/dist/seal-key-rotation.d.ts +38 -0
  68. package/dist/seal-key-rotation.d.ts.map +1 -0
  69. package/dist/seal-key-rotation.js +206 -0
  70. package/dist/seal-key-rotation.js.map +1 -0
  71. package/dist/stack-contract.d.ts +206 -3
  72. package/dist/stack-contract.d.ts.map +1 -1
  73. package/dist/stack-contract.js +219 -4
  74. package/dist/stack-contract.js.map +1 -1
  75. package/dist/stack-converge.d.ts +53 -1
  76. package/dist/stack-converge.d.ts.map +1 -1
  77. package/dist/stack-converge.js +124 -4
  78. package/dist/stack-converge.js.map +1 -1
  79. package/dist/state-lock-lease.d.ts +142 -0
  80. package/dist/state-lock-lease.d.ts.map +1 -0
  81. package/dist/state-lock-lease.js +347 -0
  82. package/dist/state-lock-lease.js.map +1 -0
  83. package/dist/state-store.d.ts +66 -9
  84. package/dist/state-store.d.ts.map +1 -1
  85. package/dist/state-store.js +249 -30
  86. package/dist/state-store.js.map +1 -1
  87. package/dist/upgrade/app-roll.d.ts +36 -7
  88. package/dist/upgrade/app-roll.d.ts.map +1 -1
  89. package/dist/upgrade/app-roll.js +53 -19
  90. package/dist/upgrade/app-roll.js.map +1 -1
  91. package/dist/upgrade/audit-job-roll.d.ts.map +1 -1
  92. package/dist/upgrade/audit-job-roll.js +3 -1
  93. package/dist/upgrade/audit-job-roll.js.map +1 -1
  94. package/dist/upgrade/converge.d.ts.map +1 -1
  95. package/dist/upgrade/converge.js +125 -12
  96. package/dist/upgrade/converge.js.map +1 -1
  97. package/dist/upgrade/gcp-lookup.d.ts +27 -10
  98. package/dist/upgrade/gcp-lookup.d.ts.map +1 -1
  99. package/dist/upgrade/gcp-lookup.js +46 -7
  100. package/dist/upgrade/gcp-lookup.js.map +1 -1
  101. package/dist/upgrade/record-rolled.d.ts +40 -0
  102. package/dist/upgrade/record-rolled.d.ts.map +1 -0
  103. package/dist/upgrade/record-rolled.js +46 -0
  104. package/dist/upgrade/record-rolled.js.map +1 -0
  105. package/dist/upgrade/upgrade.d.ts +45 -1
  106. package/dist/upgrade/upgrade.d.ts.map +1 -1
  107. package/dist/upgrade/upgrade.js +60 -17
  108. package/dist/upgrade/upgrade.js.map +1 -1
  109. package/dist/upgrader-assess.d.ts +15 -1
  110. package/dist/upgrader-assess.d.ts.map +1 -1
  111. package/dist/upgrader-assess.js +36 -6
  112. package/dist/upgrader-assess.js.map +1 -1
  113. package/dist/upgrader-gcp.d.ts +15 -0
  114. package/dist/upgrader-gcp.d.ts.map +1 -1
  115. package/dist/upgrader-gcp.js +42 -7
  116. package/dist/upgrader-gcp.js.map +1 -1
  117. package/dist/upgrader-iam-preflight.d.ts +123 -0
  118. package/dist/upgrader-iam-preflight.d.ts.map +1 -0
  119. package/dist/upgrader-iam-preflight.js +414 -0
  120. package/dist/upgrader-iam-preflight.js.map +1 -0
  121. package/dist/upgrader-job.d.ts +33 -9
  122. package/dist/upgrader-job.d.ts.map +1 -1
  123. package/dist/upgrader-job.js +169 -27
  124. package/dist/upgrader-job.js.map +1 -1
  125. package/dist/upgrader-records.d.ts +58 -0
  126. package/dist/upgrader-records.d.ts.map +1 -0
  127. package/dist/upgrader-records.js +87 -0
  128. package/dist/upgrader-records.js.map +1 -0
  129. package/dist/upgrader-reporter.d.ts +3 -2
  130. package/dist/upgrader-reporter.d.ts.map +1 -1
  131. package/dist/upgrader-reporter.js +10 -2
  132. package/dist/upgrader-reporter.js.map +1 -1
  133. package/dist/upgrader-setup.d.ts +25 -3
  134. package/dist/upgrader-setup.d.ts.map +1 -1
  135. package/dist/upgrader-setup.js +123 -11
  136. package/dist/upgrader-setup.js.map +1 -1
  137. package/dist/wizards/gcp-cost.d.ts.map +1 -1
  138. package/dist/wizards/gcp-cost.js +11 -3
  139. package/dist/wizards/gcp-cost.js.map +1 -1
  140. package/dist/wizards/gcp-pulumi.d.ts +6 -0
  141. package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
  142. package/dist/wizards/gcp-pulumi.js +14 -2
  143. package/dist/wizards/gcp-pulumi.js.map +1 -1
  144. package/dist/wizards/gcp.d.ts.map +1 -1
  145. package/dist/wizards/gcp.js +106 -4
  146. package/dist/wizards/gcp.js.map +1 -1
  147. package/package.json +2 -2
  148. package/src/agent/run.test.ts +14 -1
  149. package/src/audit-job-setup.test.ts +7 -1
  150. package/src/cli-routing.ts +1 -1
  151. package/src/cli.ts +4 -1
  152. package/src/compose.ts +5 -0
  153. package/src/converge-checkpoint.ts +75 -0
  154. package/src/converge-entrypoint.test.ts +213 -0
  155. package/src/converge-job-gcp.test.ts +222 -0
  156. package/src/converge-job-gcp.ts +443 -0
  157. package/src/converge-job-setup.test.ts +152 -0
  158. package/src/converge-job-setup.ts +268 -0
  159. package/src/converge-job.test.ts +486 -0
  160. package/src/converge-job.ts +542 -0
  161. package/src/gateway-env-isolation.test.ts +8 -1
  162. package/src/gcp-names.ts +15 -0
  163. package/src/gcp-url-map.test.ts +9 -1
  164. package/src/index.ts +8 -0
  165. package/src/infra-contract.test.ts +8 -4
  166. package/src/infra-contract.ts +33 -1
  167. package/src/install-job.test.ts +3 -1
  168. package/src/install-job.ts +31 -14
  169. package/src/lifecycle.ts +137 -71
  170. package/src/operator-access.test.ts +24 -1
  171. package/src/operator-access.ts +44 -6
  172. package/src/release-contract.ts +5 -2
  173. package/src/release-manifest.test.ts +42 -0
  174. package/src/release-manifest.ts +2 -0
  175. package/src/remote-mcp-edge.ts +137 -0
  176. package/src/remote-mcp.test.ts +690 -0
  177. package/src/remote-mcp.ts +524 -0
  178. package/src/runtime-secrets.test.ts +31 -6
  179. package/src/runtime-secrets.ts +41 -3
  180. package/src/seal-key-rotation.test.ts +131 -0
  181. package/src/seal-key-rotation.ts +258 -0
  182. package/src/stack-contract-parity.test.ts +20 -3
  183. package/src/stack-contract.test.ts +32 -2
  184. package/src/stack-contract.ts +363 -4
  185. package/src/stack-converge-secrets.test.ts +4 -0
  186. package/src/stack-converge.test.ts +21 -5
  187. package/src/stack-converge.ts +162 -7
  188. package/src/state-attach.test.ts +7 -1
  189. package/src/state-lock-lease.test.ts +302 -0
  190. package/src/state-lock-lease.ts +423 -0
  191. package/src/state-lock.test.ts +568 -0
  192. package/src/state-store.ts +347 -27
  193. package/src/upgrade/app-roll.ts +102 -21
  194. package/src/upgrade/audit-job-roll.ts +3 -1
  195. package/src/upgrade/converge.ts +148 -10
  196. package/src/upgrade/gcp-lookup.test.ts +80 -0
  197. package/src/upgrade/gcp-lookup.ts +65 -8
  198. package/src/upgrade/record-rolled.test.ts +105 -0
  199. package/src/upgrade/record-rolled.ts +91 -0
  200. package/src/upgrade/upgrade.test.ts +203 -3
  201. package/src/upgrade/upgrade.ts +120 -24
  202. package/src/upgrader-assess.test.ts +92 -3
  203. package/src/upgrader-assess.ts +58 -9
  204. package/src/upgrader-gcp.ts +47 -8
  205. package/src/upgrader-iam-preflight.test.ts +393 -0
  206. package/src/upgrader-iam-preflight.ts +510 -0
  207. package/src/upgrader-job.test.ts +586 -15
  208. package/src/upgrader-job.ts +237 -53
  209. package/src/upgrader-records.ts +151 -0
  210. package/src/upgrader-reporter.test.ts +6 -0
  211. package/src/upgrader-reporter.ts +7 -2
  212. package/src/upgrader-setup.test.ts +3 -3
  213. package/src/upgrader-setup.ts +128 -11
  214. package/src/wizards/gcp-cost.ts +12 -3
  215. package/src/wizards/gcp-pulumi.test.ts +15 -0
  216. package/src/wizards/gcp-pulumi.ts +18 -2
  217. package/src/wizards/gcp.ts +134 -4
  218. package/stacks/aws/index.ts +10 -0
  219. package/stacks/azure/index.ts +9 -0
  220. package/stacks/gcp/index.ts +47 -7
  221. package/stacks/gcp-firebase/index.ts +38 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converge-checkpoint.js","sourceRoot":"","sources":["../src/converge-checkpoint.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG/F,MAAM,OAAO,GAAG,4CAA4C,CAAC;AAE7D,MAAM,CAAC,MAAM,wBAAwB,GAAG,sBAAsB,CAAC,MAAM,CAAC;IACpE,0CAA0C;IAC1C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;IACxC,4FAA4F;IAC5F,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;IACtC,+DAA+D;IAC/D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IAC5B,MAAM,EAAE,CAAC;SACN,MAAM,CAAC;QACN,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;KAC5B,CAAC;SACD,QAAQ,EAAE;IACb,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC9F,CAAC,CAAC;AACH;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC;AAKhD,kDAAkD;AAClD,MAAM,UAAU,qBAAqB,CAAC,MAAc;IAClD,OAAO,QAAQ,MAAM,IAAI,qBAAqB,oBAAoB,CAAC;AACrE,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,sBAAsB,CAAC,MAAc,EAAE,GAAe;IACpE,OAAO,gBAAgB,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,wBAAwB,EAAE,GAAG,CAAC,CAAC;AACxF,CAAC;AAED,8BAA8B;AAC9B,MAAM,UAAU,uBAAuB,CACrC,MAAc,EACd,UAA8B,EAC9B,GAAe;IAEf,iBAAiB,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,wBAAwB,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;AAC9F,CAAC"}
@@ -0,0 +1,46 @@
1
+ import type { ConvergeJobDeps, ConvergeQueue } from "./converge-job.js";
2
+ import { type InstallMetadata } from "./install-state.js";
3
+ import { type UpgraderPlacement } from "./upgrader-gcp.js";
4
+ import type { JobLog } from "./upgrader-reporter.js";
5
+ /**
6
+ * The image digest an execution of the converge job runs, from its Cloud
7
+ * Run description (the execution's task template names the image it was
8
+ * started with). Null when it cannot be read or names no digest.
9
+ */
10
+ export declare function executionImageDigest(describeJson: string): string | null;
11
+ /**
12
+ * Why install.json's Owner email does not match the IAP members the
13
+ * deployed operator-access job admits (operator-access.ts deploys them as
14
+ * `installIapAllowlist(ownerEmail)`), or null when it does. Read from
15
+ * `gcloud run jobs describe --format=json` (v1 or v2 shape).
16
+ */
17
+ export declare function deployedOwnerMismatch(describeJson: string, ownerEmail: string): string | null;
18
+ /**
19
+ * Why install.json's site does not match what the admin serves today, or
20
+ * null when it does (#883 review, round 2). install.json is writable by the
21
+ * upgrader's account, and the converge hands its domain, staging host and
22
+ * region to code running as the provisioner: a tampered record would have
23
+ * the provisioner point the site, its certificate and its IAP gate at
24
+ * another domain. So the job converges only onto the site the deployed
25
+ * admin already serves (`CAELO_SITE_URL`, `CAELO_STAGING_HOST`, from
26
+ * `gcloud run services describe --format=json`) in the region this job
27
+ * runs in. A change of domain is a terminal upgrade by the Owner.
28
+ *
29
+ * @param adminJson the admin service's description (v1 or v2 shape)
30
+ * @param region the region this job runs in (the metadata server's)
31
+ */
32
+ export declare function deployedSiteMismatch(adminJson: string, meta: Pick<InstallMetadata, "domain" | "stagingDomain" | "region">, region: string): string | null;
33
+ /**
34
+ * Why `CLOUD_RUN_EXECUTION` cannot name a run of the converge job, or null
35
+ * when it can. The name keys the state lock's holder and the hand-over
36
+ * between the job's two stages, so a value that names another job's run
37
+ * (or is not a Cloud Run name at all) stops the job before it acts
38
+ * (#883 review). Cloud Run sets it and rejects user values for it; this is
39
+ * the second line.
40
+ */
41
+ export declare function convergeExecutionNameError(execution: string | null): string | null;
42
+ /** The new execution's name from `gcloud run jobs execute --async`. */
43
+ export declare function startedExecutionName(stdout: string, stderr: string): string | null;
44
+ /** Every dependency of {@link runConvergeJob} except the database and the log. */
45
+ export declare function gcpConvergeDeps(placement: UpgraderPlacement, queue: ConvergeQueue, log: JobLog): ConvergeJobDeps;
46
+ //# sourceMappingURL=converge-job-gcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converge-job-gcp.d.ts","sourceRoot":"","sources":["../src/converge-job-gcp.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAA0B,MAAM,mBAAmB,CAAC;AAYhG,OAAO,EACL,KAAK,eAAe,EAKrB,MAAM,oBAAoB,CAAC;AAY5B,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAIrD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBxE;AAQD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkC7F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,eAAe,GAAG,QAAQ,CAAC,EAClE,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAiCf;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAOlF;AAED,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGlF;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAC7B,SAAS,EAAE,iBAAiB,EAC5B,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,GACV,eAAe,CAwOjB"}
@@ -0,0 +1,368 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * The real side effects of the converge job on Google Cloud (#819):
4
+ * gcloud as the job's own identity (the install's caelo-provisioner), the
5
+ * install's ops bucket for install.json, the state lock and the checkpoint,
6
+ * the fixed release registry, cosign, and — for stage 2 — the terminal's
7
+ * upgrade itself (upgrade/upgrade.ts) wired the way lifecycle.ts wires it,
8
+ * minus the operator-identity step: this run IS the provisioner.
9
+ * converge-job.ts takes them as {@link ConvergeJobDeps}; the database queue
10
+ * and the job log come from `@caelo-cms/platform-updater`.
11
+ *
12
+ * Nothing here reads the process env or argv (CLOUD_RUN_EXECUTION, read by
13
+ * the entry point, only names this run): what the job may install and from
14
+ * where is compiled in (release-manifest.ts's registry + signer), and where
15
+ * it runs comes from the metadata server.
16
+ */
17
+ import { mkdtempSync } from "node:fs";
18
+ import { tmpdir } from "node:os";
19
+ import { join } from "node:path";
20
+ import { CAELO_VERSION } from "@caelo-cms/shared";
21
+ import { readConvergeCheckpoint, writeConvergeCheckpoint } from "./converge-checkpoint.js";
22
+ import { CONVERGE_TASK_TIMEOUT_MINUTES } from "./converge-job-setup.js";
23
+ import { gcloud } from "./gcloud.js";
24
+ import { realSleep } from "./gcloud-retry.js";
25
+ import { convergeJobName, GCP_STACK_ENV, gcpNamePrefix, operatorAccessJobName, } from "./gcp-names.js";
26
+ import { INFRA_CONTRACT_VERSION } from "./infra-contract.js";
27
+ import { describeExecution } from "./install-job.js";
28
+ import { installRoot, installStagingHost, readMetadata, recordInfraContractVersion, } from "./install-state.js";
29
+ import { runMigrationsViaCloudRunJob } from "./migration-runner.js";
30
+ import { installIapAllowlist } from "./operator-access.js";
31
+ import { fetchVerifiedReleaseManifest } from "./release-manifest.js";
32
+ import { publicSiteUrl, STAGING_HOST_ENV } from "./stack-contract.js";
33
+ import { attachInstall } from "./state-attach.js";
34
+ import { hasLocalPulumiState, opsBucketName } from "./state-backend.js";
35
+ import { acquireBucketStateLock, GcsStateStore, realSyncGcloud } from "./state-store.js";
36
+ import { resolveGcpResourceName } from "./upgrade/gcp-lookup.js";
37
+ import { releaseImageRef, verifyCosignAll } from "./upgrade/release-images.js";
38
+ import { upgradeGcpInstallOutcome } from "./upgrade/upgrade.js";
39
+ import { healthProbeFor } from "./upgrader-gcp.js";
40
+ const DIGEST = /@(sha256:[0-9a-f]{64})/;
41
+ /**
42
+ * The image digest an execution of the converge job runs, from its Cloud
43
+ * Run description (the execution's task template names the image it was
44
+ * started with). Null when it cannot be read or names no digest.
45
+ */
46
+ export function executionImageDigest(describeJson) {
47
+ let parsed;
48
+ try {
49
+ parsed = JSON.parse(describeJson);
50
+ }
51
+ catch {
52
+ return null;
53
+ }
54
+ // gcloud prints the v1 resource (spec.template.spec.containers); the v2
55
+ // shape (template.containers) is accepted too. The first container is it.
56
+ const p = parsed;
57
+ const image = p.spec?.template?.spec?.containers?.[0]?.image ?? p.template?.containers?.[0]?.image ?? "";
58
+ return DIGEST.exec(image)?.[1] ?? null;
59
+ }
60
+ /** The operator-access job's env var listing the install's fixed IAP members. */
61
+ const STATIC_MEMBERS_ENV = "CAELO_OPERATOR_ACCESS_STATIC_MEMBERS";
62
+ /** The admin env var naming the public site (stack-contract.ts adminEnvContract). */
63
+ const SITE_URL_ENV = "CAELO_SITE_URL";
64
+ /**
65
+ * Why install.json's Owner email does not match the IAP members the
66
+ * deployed operator-access job admits (operator-access.ts deploys them as
67
+ * `installIapAllowlist(ownerEmail)`), or null when it does. Read from
68
+ * `gcloud run jobs describe --format=json` (v1 or v2 shape).
69
+ */
70
+ export function deployedOwnerMismatch(describeJson, ownerEmail) {
71
+ let parsed;
72
+ try {
73
+ parsed = JSON.parse(describeJson);
74
+ }
75
+ catch {
76
+ return "the operator-access job's description is not JSON";
77
+ }
78
+ const p = parsed;
79
+ const env = p.spec?.template?.spec?.template?.spec?.containers?.[0]?.env ??
80
+ p.template?.template?.containers?.[0]?.env ??
81
+ [];
82
+ const deployed = env.find((e) => e.name === STATIC_MEMBERS_ENV)?.value;
83
+ if (deployed === undefined)
84
+ return `the operator-access job sets no ${STATIC_MEMBERS_ENV}`;
85
+ const want = installIapAllowlist(ownerEmail).join(",");
86
+ const have = deployed
87
+ .split(",")
88
+ .map((m) => m.trim().toLowerCase())
89
+ .filter(Boolean)
90
+ .sort()
91
+ .join(",");
92
+ if (have !== [...installIapAllowlist(ownerEmail)].sort().join(",")) {
93
+ return `the admin admits ${deployed || "nobody"}, the records would make it ${want}`;
94
+ }
95
+ return null;
96
+ }
97
+ /**
98
+ * Why install.json's site does not match what the admin serves today, or
99
+ * null when it does (#883 review, round 2). install.json is writable by the
100
+ * upgrader's account, and the converge hands its domain, staging host and
101
+ * region to code running as the provisioner: a tampered record would have
102
+ * the provisioner point the site, its certificate and its IAP gate at
103
+ * another domain. So the job converges only onto the site the deployed
104
+ * admin already serves (`CAELO_SITE_URL`, `CAELO_STAGING_HOST`, from
105
+ * `gcloud run services describe --format=json`) in the region this job
106
+ * runs in. A change of domain is a terminal upgrade by the Owner.
107
+ *
108
+ * @param adminJson the admin service's description (v1 or v2 shape)
109
+ * @param region the region this job runs in (the metadata server's)
110
+ */
111
+ export function deployedSiteMismatch(adminJson, meta, region) {
112
+ if (meta.region !== region) {
113
+ return `the records name region ${meta.region ?? "none"}, the converge job runs in ${region}`;
114
+ }
115
+ let parsed;
116
+ try {
117
+ parsed = JSON.parse(adminJson);
118
+ }
119
+ catch {
120
+ return "the admin's description is not JSON";
121
+ }
122
+ const p = parsed;
123
+ const env = p.spec?.template?.spec?.containers?.[0]?.env ?? p.template?.containers?.[0]?.env ?? [];
124
+ const value = (name) => env.find((e) => e.name === name)?.value;
125
+ const site = value(SITE_URL_ENV);
126
+ if (site === undefined)
127
+ return `the admin sets no ${SITE_URL_ENV}`;
128
+ if (site !== publicSiteUrl(meta.domain)) {
129
+ return `the admin serves ${site}, the records would make it ${publicSiteUrl(meta.domain)}`;
130
+ }
131
+ // An admin from before #650 has no staging host yet; this converge adds
132
+ // it, but only the default one derived from the domain.
133
+ const staging = value(STAGING_HOST_ENV);
134
+ const want = installStagingHost(meta);
135
+ const defaultHost = installStagingHost({ domain: meta.domain });
136
+ if (staging === undefined ? want !== defaultHost : staging !== want) {
137
+ return `the admin's staging host is ${staging ?? "unset"}, the records would make it ${want}`;
138
+ }
139
+ return null;
140
+ }
141
+ /**
142
+ * Why `CLOUD_RUN_EXECUTION` cannot name a run of the converge job, or null
143
+ * when it can. The name keys the state lock's holder and the hand-over
144
+ * between the job's two stages, so a value that names another job's run
145
+ * (or is not a Cloud Run name at all) stops the job before it acts
146
+ * (#883 review). Cloud Run sets it and rejects user values for it; this is
147
+ * the second line.
148
+ */
149
+ export function convergeExecutionNameError(execution) {
150
+ if (execution === null)
151
+ return null;
152
+ const prefix = `${convergeJobName(GCP_STACK_ENV)}-`;
153
+ if (!/^[a-z0-9-]{1,63}$/.test(execution) || !execution.startsWith(prefix)) {
154
+ return `CLOUD_RUN_EXECUTION is "${execution.slice(0, 80)}", not a run of ${convergeJobName(GCP_STACK_ENV)}`;
155
+ }
156
+ return null;
157
+ }
158
+ /** The new execution's name from `gcloud run jobs execute --async`. */
159
+ export function startedExecutionName(stdout, stderr) {
160
+ const name = stdout.trim().split(/\s+/)[0] || /Execution \[([^\]]+)\]/.exec(stderr)?.[1] || "";
161
+ return /^[a-z0-9-]+$/.test(name) ? name : null;
162
+ }
163
+ /** Every dependency of {@link runConvergeJob} except the database and the log. */
164
+ export function gcpConvergeDeps(placement, queue, log) {
165
+ const run = gcloud;
166
+ const http = fetch;
167
+ const { projectId, region } = placement;
168
+ const bucket = opsBucketName(projectId);
169
+ const job = convergeJobName(GCP_STACK_ENV);
170
+ const location = [`--region=${region}`, `--project=${projectId}`];
171
+ // Peeks only (uncached); the upgrade writes through install-state.ts.
172
+ const store = new GcsStateStore(bucket, mkdtempSync(join(tmpdir(), "caelo-converge-")));
173
+ const upgrade = async ({ manifest: m, reporter, resume, onCheckpoint, }) => {
174
+ // The container starts empty: mirror the install from its bucket, as
175
+ // the install job does, so install-state.ts reads and writes it there.
176
+ const attached = attachInstall(projectId, {
177
+ run: realSyncGcloud,
178
+ rootFor: installRoot,
179
+ hasLocalState: hasLocalPulumiState,
180
+ });
181
+ if (!attached.ok) {
182
+ reporter.error(`Could not read the install's records: ${attached.error}`);
183
+ return { ok: false, rolledBack: false, unrecorded: false };
184
+ }
185
+ const installId = attached.installId;
186
+ // Lazily: the CLI's lifecycle module (clack, the wizards' Pulumi
187
+ // helpers) is only needed by stage 2, never by the package's importers.
188
+ const { recordRolledRelease } = await import("./lifecycle.js");
189
+ const meta = readMetadata(installId);
190
+ if ((meta.provider !== "gcp" && meta.provider !== "gcp-firebase") || !meta.region) {
191
+ reporter.error(`install.json of ${installId} is not a Google Cloud install with a region.`);
192
+ return { ok: false, rolledBack: false, unrecorded: false };
193
+ }
194
+ // #883 review — install.json is writable by the upgrader's account
195
+ // (install/ in the ops bucket), and this job runs as the provisioner:
196
+ // the Owner email it hands the converge decides who passes the admin's
197
+ // IAP gate. Converge only when it matches what is deployed today; a
198
+ // change of Owner is a terminal upgrade by the Owner.
199
+ const access = await run([
200
+ "run",
201
+ "jobs",
202
+ "describe",
203
+ operatorAccessJobName(GCP_STACK_ENV),
204
+ ...location,
205
+ "--format=json",
206
+ ]);
207
+ const ownerCheck = access.ok
208
+ ? deployedOwnerMismatch(access.stdout, meta.ownerEmail)
209
+ : `the deployed operator-access job could not be read (${access.stderr.trim()})`;
210
+ if (ownerCheck) {
211
+ reporter.error(`Nothing was changed: the install's records name ${meta.ownerEmail} as Owner, which this update could not confirm against the admin's current access settings (${ownerCheck}). Run the update once from Cloud Shell or the computer you installed from.`);
212
+ return { ok: false, rolledBack: false, unrecorded: false };
213
+ }
214
+ const admin = await resolveGcpResourceName(run, "run-service", `${gcpNamePrefix(GCP_STACK_ENV)}-admin`, projectId, region);
215
+ const described = admin
216
+ ? await run(["run", "services", "describe", admin, ...location, "--format=json"])
217
+ : null;
218
+ const siteCheck = !admin
219
+ ? "the admin service could not be found"
220
+ : described?.ok
221
+ ? deployedSiteMismatch(described.stdout, meta, region)
222
+ : `the admin's description could not be read (${described?.stderr.trim() ?? ""})`;
223
+ if (siteCheck) {
224
+ reporter.error(`Nothing was changed: the install's records name ${meta.domain} in ${meta.region}, which this update could not confirm against what the admin serves today (${siteCheck}). Run the update once from Cloud Shell or the computer you installed from.`);
225
+ return { ok: false, rolledBack: false, unrecorded: false };
226
+ }
227
+ let recorded = true;
228
+ let converged = false;
229
+ const outcome = await upgradeGcpInstallOutcome({
230
+ provider: meta.provider,
231
+ projectId,
232
+ region: meta.region,
233
+ env: GCP_STACK_ENV,
234
+ domain: meta.domain,
235
+ stagingHost: installStagingHost(meta),
236
+ ownerEmail: meta.ownerEmail,
237
+ targetTag: m.version,
238
+ // This code is the target release's (stage 2), so its contract is it.
239
+ infraContractVersion: INFRA_CONTRACT_VERSION,
240
+ skipVerify: false,
241
+ skipHealthCheck: false,
242
+ migrationsContract: m.migrations.contract,
243
+ }, {
244
+ run,
245
+ http,
246
+ sleep: realSleep,
247
+ reporter,
248
+ // The signed manifest's digests — never a registry tag lookup.
249
+ resolveImages: async () => ({
250
+ ok: true,
251
+ images: {
252
+ admin: { digest: m.digests.admin, imageRef: releaseImageRef("admin", m.digests.admin) },
253
+ gateway: {
254
+ digest: m.digests.gateway,
255
+ imageRef: releaseImageRef("gateway", m.digests.gateway),
256
+ },
257
+ },
258
+ }),
259
+ verifyImages: verifyCosignAll,
260
+ migrate: (imageRef) => runMigrationsViaCloudRunJob({ projectId, region: meta.region, imageOverride: imageRef }, { run }),
261
+ healthProbe: (plan) => healthProbeFor(run, http, plan),
262
+ recordDigests: async (digests) => {
263
+ recorded = await recordRolledRelease(installId, meta.provider, digests, m.version);
264
+ },
265
+ resolveOpsImage: async () => releaseImageRef("ops", m.digests.ops),
266
+ recordInfraContractVersion: (version) => {
267
+ recordInfraContractVersion(installId, version);
268
+ converged = true;
269
+ },
270
+ ...(resume ? { resume } : {}),
271
+ onCheckpoint,
272
+ });
273
+ // rolled_back only when the rollback really put the previous release
274
+ // back (app-roll.ts reports it structurally), never from log text.
275
+ const result = outcome.ok && recorded
276
+ ? { ok: true, converged }
277
+ : {
278
+ ok: false,
279
+ rolledBack: !outcome.ok && outcome.rolledBack,
280
+ unrecorded: outcome.ok && !recorded,
281
+ };
282
+ return result;
283
+ };
284
+ return {
285
+ queue,
286
+ projectId,
287
+ execution: placement.execution,
288
+ ownVersion: CAELO_VERSION,
289
+ // The default deps: the fixed registry and signer, never overridden.
290
+ fetchManifest: (version) => fetchVerifiedReleaseManifest(version),
291
+ readInstall: () => {
292
+ const text = store.peek("install.json");
293
+ return text === null ? null : JSON.parse(text);
294
+ },
295
+ verifyImage: (slug, digest) => verifyCosignAll([{ slug, digest }]),
296
+ ownImageDigest: async () => {
297
+ if (!placement.execution)
298
+ return null;
299
+ const r = await run([
300
+ "run",
301
+ "jobs",
302
+ "executions",
303
+ "describe",
304
+ placement.execution,
305
+ ...location,
306
+ "--format=json",
307
+ ]);
308
+ return r.ok ? executionImageDigest(r.stdout) : null;
309
+ },
310
+ pointJobAt: async (digest) => {
311
+ // Only the image changes: the identity, command and args stay what
312
+ // converge-job-setup.ts deployed.
313
+ const update = await run([
314
+ "run",
315
+ "jobs",
316
+ "update",
317
+ job,
318
+ `--image=${releaseImageRef("ops", digest)}`,
319
+ ...location,
320
+ "--quiet",
321
+ ]);
322
+ return update.ok
323
+ ? { ok: true }
324
+ : { ok: false, error: `update ${job}: ${update.stderr.trim()}` };
325
+ },
326
+ startJob: async () => {
327
+ const exec = await run([
328
+ "run",
329
+ "jobs",
330
+ "execute",
331
+ job,
332
+ ...location,
333
+ "--async",
334
+ "--format=value(metadata.name)",
335
+ ]);
336
+ if (!exec.ok)
337
+ return { ok: false, error: `start ${job}: ${exec.stderr.trim()}` };
338
+ const execution = startedExecutionName(exec.stdout, exec.stderr);
339
+ if (!execution) {
340
+ return {
341
+ ok: false,
342
+ error: `${job} started but gcloud did not name the execution (${exec.stderr.trim()})`,
343
+ };
344
+ }
345
+ return { ok: true, execution };
346
+ },
347
+ executionState: (execution) => describeExecution(run, { projectId, region, execution }),
348
+ // #815 — the lock names this execution; a later run breaks it once
349
+ // Cloud Run says this one has ended (killed at its task timeout).
350
+ lockState: (onBreak) => acquireBucketStateLock(bucket, "caelo converge job", realSyncGcloud, {
351
+ onBreak,
352
+ ...(placement.execution
353
+ ? {
354
+ holder: {
355
+ execution: { projectId, region, name: placement.execution },
356
+ maxRuntimeMs: CONVERGE_TASK_TIMEOUT_MINUTES * 60_000,
357
+ },
358
+ }
359
+ : {}),
360
+ }),
361
+ readCheckpoint: () => readConvergeCheckpoint(bucket, realSyncGcloud),
362
+ writeCheckpoint: (checkpoint) => writeConvergeCheckpoint(bucket, checkpoint, realSyncGcloud),
363
+ upgrade,
364
+ now: () => new Date(),
365
+ log,
366
+ };
367
+ }
368
+ //# sourceMappingURL=converge-job-gcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converge-job-gcp.js","sourceRoot":"","sources":["../src/converge-job-gcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import { type GcloudRunner, type Sleep } from "./gcloud-retry.js";
2
+ /**
3
+ * The job's task timeout in minutes, and the lease on the state lock it
4
+ * holds (state-lock-lease.ts): after it, Cloud Run has killed the run and a
5
+ * new execution resumes from the checkpoint. A converge plus a roll takes
6
+ * 10–20 minutes; the live 0.10.51 run needed 7 before its roll.
7
+ */
8
+ export declare const CONVERGE_TASK_TIMEOUT_MINUTES = 60;
9
+ /**
10
+ * Exactly what the admin's runtime service account may do on the converge
11
+ * job — start it (no overrides) and read its runs. The setup grants these
12
+ * two and nothing else; the tests assert it.
13
+ */
14
+ export declare const CONVERGE_ADMIN_ROLES: readonly ["roles/run.jobsExecutor", "roles/run.viewer"];
15
+ /**
16
+ * The job's entry point and its one argument. `caelo-converge-job`
17
+ * (packages/provisioning/ops/caelo-converge-job, installed by
18
+ * Dockerfile.ops) refuses every other argument and starts the job with a
19
+ * scrubbed environment, so even an execution override could not turn the
20
+ * provisioner's job into `destroy` or point gcloud/Pulumi elsewhere
21
+ * (#883 review). Nobody holds run.jobs.runWithOverrides on it anyway.
22
+ */
23
+ export declare const CONVERGE_JOB_ENTRYPOINT = "caelo-converge-job";
24
+ export declare const CONVERGE_JOB_COMMAND = "converge-job";
25
+ export interface ConvergeSetupTarget {
26
+ readonly projectId: string;
27
+ readonly region: string;
28
+ /** Pulumi stack name (`production`). */
29
+ readonly env: string;
30
+ /** The caelo-ops image to run, digest-pinned (`…/ops@sha256:…`). */
31
+ readonly opsImageRef: string;
32
+ /** VPC the admin uses to reach Cloud SQL's private IP (the job's queue does too). */
33
+ readonly network: string;
34
+ readonly subnet: string;
35
+ }
36
+ export type ConvergeSetupResult = {
37
+ readonly ok: true;
38
+ readonly done: string[];
39
+ } | {
40
+ readonly ok: false;
41
+ readonly done: string[];
42
+ readonly error: string;
43
+ /**
44
+ * `no-provisioner`: this install has no caelo-provisioner, which the
45
+ * job would run as. Not a failure of the converge (#883 review): such
46
+ * an install keeps installing cloud-setup releases from a terminal,
47
+ * and its admin, without CAELO_CONVERGE_JOB, says so.
48
+ */
49
+ readonly reason?: "no-provisioner";
50
+ };
51
+ /**
52
+ * The `gcloud run jobs deploy` argv of the converge job: the ops image by
53
+ * digest, the provisioner as its identity, no env and no secrets, the one
54
+ * fixed subcommand. Exported for the tests that pin the boundary.
55
+ */
56
+ export declare function convergeJobDeployArgs(target: ConvergeSetupTarget): string[];
57
+ /** Ensure the converge job and everything it needs. Never throws for a gcloud failure. */
58
+ export declare function ensureConvergeJob(target: ConvergeSetupTarget, deps?: {
59
+ run?: GcloudRunner;
60
+ sleep?: Sleep;
61
+ }): Promise<ConvergeSetupResult>;
62
+ //# sourceMappingURL=converge-job-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converge-job-setup.d.ts","sourceRoot":"","sources":["../src/converge-job-setup.ts"],"names":[],"mappings":"AAmDA,OAAO,EAAE,KAAK,YAAY,EAA2B,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAO3F;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,yDAA0D,CAAC;AAE5F;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,uBAAuB,CAAC;AAC5D,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AAMnD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAC9C;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAC;CACpC,CAAC;AAEN;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,EAAE,CA4B3E;AAED,0FAA0F;AAC1F,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,mBAAmB,EAC3B,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,YAAY,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAO,GAC/C,OAAO,CAAC,mBAAmB,CAAC,CAiH9B"}