@caelo-cms/provisioning 0.11.9 → 0.11.11

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 (352) hide show
  1. package/dist/adapter.d.ts +6 -0
  2. package/dist/adapter.d.ts.map +1 -1
  3. package/dist/admin-domain.d.ts +10 -1
  4. package/dist/admin-domain.d.ts.map +1 -1
  5. package/dist/admin-domain.js +13 -3
  6. package/dist/admin-domain.js.map +1 -1
  7. package/dist/adopt-existing.d.ts +12 -3
  8. package/dist/adopt-existing.d.ts.map +1 -1
  9. package/dist/adopt-existing.js +143 -0
  10. package/dist/adopt-existing.js.map +1 -1
  11. package/dist/agent/command.d.ts +23 -0
  12. package/dist/agent/command.d.ts.map +1 -1
  13. package/dist/agent/command.js +32 -9
  14. package/dist/agent/command.js.map +1 -1
  15. package/dist/agent/run.d.ts +2 -0
  16. package/dist/agent/run.d.ts.map +1 -1
  17. package/dist/agent/run.js +5 -1
  18. package/dist/agent/run.js.map +1 -1
  19. package/dist/agent-db.js +69 -10
  20. package/dist/aws-task-roles.d.ts +4 -2
  21. package/dist/aws-task-roles.d.ts.map +1 -1
  22. package/dist/aws-task-roles.js +4 -1
  23. package/dist/aws-task-roles.js.map +1 -1
  24. package/dist/caddy.d.ts +21 -4
  25. package/dist/caddy.d.ts.map +1 -1
  26. package/dist/caddy.js +27 -3
  27. package/dist/caddy.js.map +1 -1
  28. package/dist/cli-routing.js +1 -1
  29. package/dist/cli-routing.js.map +1 -1
  30. package/dist/cli.js +68 -7
  31. package/dist/cli.js.map +1 -1
  32. package/dist/cloudsql-tls.d.ts +93 -0
  33. package/dist/cloudsql-tls.d.ts.map +1 -0
  34. package/dist/cloudsql-tls.js +295 -0
  35. package/dist/cloudsql-tls.js.map +1 -0
  36. package/dist/compose.d.ts +43 -6
  37. package/dist/compose.d.ts.map +1 -1
  38. package/dist/compose.js +148 -23
  39. package/dist/compose.js.map +1 -1
  40. package/dist/converge-checkpoint.d.ts +1 -0
  41. package/dist/converge-checkpoint.d.ts.map +1 -1
  42. package/dist/converge-checkpoint.js +8 -1
  43. package/dist/converge-checkpoint.js.map +1 -1
  44. package/dist/converge-db-trust.d.ts +44 -0
  45. package/dist/converge-db-trust.d.ts.map +1 -0
  46. package/dist/converge-db-trust.js +158 -0
  47. package/dist/converge-db-trust.js.map +1 -0
  48. package/dist/converge-job-gcp.d.ts +5 -2
  49. package/dist/converge-job-gcp.d.ts.map +1 -1
  50. package/dist/converge-job-gcp.js +11 -13
  51. package/dist/converge-job-gcp.js.map +1 -1
  52. package/dist/converge-job-preflight.d.ts.map +1 -1
  53. package/dist/converge-job-preflight.js +8 -0
  54. package/dist/converge-job-preflight.js.map +1 -1
  55. package/dist/converge-job.d.ts +17 -0
  56. package/dist/converge-job.d.ts.map +1 -1
  57. package/dist/converge-job.js +12 -0
  58. package/dist/converge-job.js.map +1 -1
  59. package/dist/deployed-release.d.ts +4 -1
  60. package/dist/deployed-release.d.ts.map +1 -1
  61. package/dist/deployed-release.js +18 -8
  62. package/dist/deployed-release.js.map +1 -1
  63. package/dist/gcp-names.d.ts +34 -0
  64. package/dist/gcp-names.d.ts.map +1 -1
  65. package/dist/gcp-names.js +45 -0
  66. package/dist/gcp-names.js.map +1 -1
  67. package/dist/gcp-url-map.d.ts.map +1 -1
  68. package/dist/gcp-url-map.js +6 -2
  69. package/dist/gcp-url-map.js.map +1 -1
  70. package/dist/index.d.ts +3 -2
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +2 -1
  73. package/dist/index.js.map +1 -1
  74. package/dist/infra-contract.d.ts +1 -1
  75. package/dist/infra-contract.d.ts.map +1 -1
  76. package/dist/infra-contract.js +45 -1
  77. package/dist/infra-contract.js.map +1 -1
  78. package/dist/install-job.d.ts +4 -2
  79. package/dist/install-job.d.ts.map +1 -1
  80. package/dist/install-job.js +4 -1
  81. package/dist/install-job.js.map +1 -1
  82. package/dist/install-state.d.ts +13 -0
  83. package/dist/install-state.d.ts.map +1 -1
  84. package/dist/install-state.js +17 -4
  85. package/dist/install-state.js.map +1 -1
  86. package/dist/lifecycle.d.ts.map +1 -1
  87. package/dist/lifecycle.js +20 -8
  88. package/dist/lifecycle.js.map +1 -1
  89. package/dist/mcp-auth-proxy-setup.d.ts +48 -0
  90. package/dist/mcp-auth-proxy-setup.d.ts.map +1 -0
  91. package/dist/mcp-auth-proxy-setup.js +280 -0
  92. package/dist/mcp-auth-proxy-setup.js.map +1 -0
  93. package/dist/migration-runner.d.ts.map +1 -1
  94. package/dist/migration-runner.js +8 -3
  95. package/dist/migration-runner.js.map +1 -1
  96. package/dist/migration-targets.d.ts +11 -0
  97. package/dist/migration-targets.d.ts.map +1 -0
  98. package/dist/migration-targets.js +12 -0
  99. package/dist/migration-targets.js.map +1 -0
  100. package/dist/operator-access.d.ts +10 -0
  101. package/dist/operator-access.d.ts.map +1 -1
  102. package/dist/operator-access.js +5 -0
  103. package/dist/operator-access.js.map +1 -1
  104. package/dist/pool-budget-stack.d.ts +13 -1
  105. package/dist/pool-budget-stack.d.ts.map +1 -1
  106. package/dist/pool-budget-stack.js +11 -1
  107. package/dist/pool-budget-stack.js.map +1 -1
  108. package/dist/public-role-isolation.d.ts +7 -3
  109. package/dist/public-role-isolation.d.ts.map +1 -1
  110. package/dist/public-role-isolation.js +25 -13
  111. package/dist/public-role-isolation.js.map +1 -1
  112. package/dist/release-contract.d.ts.map +1 -1
  113. package/dist/release-contract.js +3 -0
  114. package/dist/release-contract.js.map +1 -1
  115. package/dist/release-manifest.d.ts +25 -1
  116. package/dist/release-manifest.d.ts.map +1 -1
  117. package/dist/release-manifest.js +36 -3
  118. package/dist/release-manifest.js.map +1 -1
  119. package/dist/remote-mcp.d.ts +55 -18
  120. package/dist/remote-mcp.d.ts.map +1 -1
  121. package/dist/remote-mcp.js +307 -77
  122. package/dist/remote-mcp.js.map +1 -1
  123. package/dist/runtime-secrets.d.ts +11 -0
  124. package/dist/runtime-secrets.d.ts.map +1 -1
  125. package/dist/runtime-secrets.js +40 -25
  126. package/dist/runtime-secrets.js.map +1 -1
  127. package/dist/scheduler-setup.d.ts +75 -0
  128. package/dist/scheduler-setup.d.ts.map +1 -0
  129. package/dist/scheduler-setup.js +331 -0
  130. package/dist/scheduler-setup.js.map +1 -0
  131. package/dist/seal-key-rotation.d.ts +7 -7
  132. package/dist/seal-key-rotation.d.ts.map +1 -1
  133. package/dist/seal-key-rotation.js +22 -22
  134. package/dist/seal-key-rotation.js.map +1 -1
  135. package/dist/self-hosted-db-tls.d.ts +37 -0
  136. package/dist/self-hosted-db-tls.d.ts.map +1 -0
  137. package/dist/self-hosted-db-tls.js +220 -0
  138. package/dist/self-hosted-db-tls.js.map +1 -0
  139. package/dist/self-hosted-release.d.ts +3 -1
  140. package/dist/self-hosted-release.d.ts.map +1 -1
  141. package/dist/self-hosted-release.js +33 -9
  142. package/dist/self-hosted-release.js.map +1 -1
  143. package/dist/self-hosted-roles.d.ts +43 -2
  144. package/dist/self-hosted-roles.d.ts.map +1 -1
  145. package/dist/self-hosted-roles.js +87 -1
  146. package/dist/self-hosted-roles.js.map +1 -1
  147. package/dist/self-hosted-scheduler-interval.d.ts +21 -0
  148. package/dist/self-hosted-scheduler-interval.d.ts.map +1 -0
  149. package/dist/self-hosted-scheduler-interval.js +68 -0
  150. package/dist/self-hosted-scheduler-interval.js.map +1 -0
  151. package/dist/self-hosted-start.d.ts +0 -21
  152. package/dist/self-hosted-start.d.ts.map +1 -1
  153. package/dist/self-hosted-start.js +39 -1
  154. package/dist/self-hosted-start.js.map +1 -1
  155. package/dist/self-hosted-upgrade.d.ts +19 -7
  156. package/dist/self-hosted-upgrade.d.ts.map +1 -1
  157. package/dist/self-hosted-upgrade.js +78 -25
  158. package/dist/self-hosted-upgrade.js.map +1 -1
  159. package/dist/stack-contract.d.ts +234 -28
  160. package/dist/stack-contract.d.ts.map +1 -1
  161. package/dist/stack-contract.js +397 -39
  162. package/dist/stack-contract.js.map +1 -1
  163. package/dist/stack-converge.d.ts +31 -0
  164. package/dist/stack-converge.d.ts.map +1 -1
  165. package/dist/stack-converge.js +71 -30
  166. package/dist/stack-converge.js.map +1 -1
  167. package/dist/staging-database.d.ts +22 -0
  168. package/dist/staging-database.d.ts.map +1 -0
  169. package/dist/staging-database.js +117 -0
  170. package/dist/staging-database.js.map +1 -0
  171. package/dist/upgrade/app-roll.d.ts +25 -4
  172. package/dist/upgrade/app-roll.d.ts.map +1 -1
  173. package/dist/upgrade/app-roll.js +63 -17
  174. package/dist/upgrade/app-roll.js.map +1 -1
  175. package/dist/upgrade/converge.d.ts +5 -0
  176. package/dist/upgrade/converge.d.ts.map +1 -1
  177. package/dist/upgrade/converge.js +207 -20
  178. package/dist/upgrade/converge.js.map +1 -1
  179. package/dist/upgrade/health.d.ts +31 -7
  180. package/dist/upgrade/health.d.ts.map +1 -1
  181. package/dist/upgrade/health.js +41 -17
  182. package/dist/upgrade/health.js.map +1 -1
  183. package/dist/upgrade/image-forms.d.ts +1 -1
  184. package/dist/upgrade/image-forms.d.ts.map +1 -1
  185. package/dist/upgrade/image-forms.js +24 -7
  186. package/dist/upgrade/image-forms.js.map +1 -1
  187. package/dist/upgrade/release-images.d.ts +12 -3
  188. package/dist/upgrade/release-images.d.ts.map +1 -1
  189. package/dist/upgrade/release-images.js +13 -4
  190. package/dist/upgrade/release-images.js.map +1 -1
  191. package/dist/upgrade/upgrade.d.ts +19 -3
  192. package/dist/upgrade/upgrade.d.ts.map +1 -1
  193. package/dist/upgrade/upgrade.js +37 -2
  194. package/dist/upgrade/upgrade.js.map +1 -1
  195. package/dist/upgrader-gcp.d.ts +13 -0
  196. package/dist/upgrader-gcp.d.ts.map +1 -1
  197. package/dist/upgrader-gcp.js +50 -1
  198. package/dist/upgrader-gcp.js.map +1 -1
  199. package/dist/upgrader-iam-preflight.d.ts.map +1 -1
  200. package/dist/upgrader-iam-preflight.js +6 -1
  201. package/dist/upgrader-iam-preflight.js.map +1 -1
  202. package/dist/upgrader-job.d.ts +1 -1
  203. package/dist/upgrader-job.d.ts.map +1 -1
  204. package/dist/upgrader-job.js +20 -14
  205. package/dist/upgrader-job.js.map +1 -1
  206. package/dist/upgrader-records.d.ts +1 -1
  207. package/dist/upgrader-records.d.ts.map +1 -1
  208. package/dist/upgrader-records.js +26 -7
  209. package/dist/upgrader-records.js.map +1 -1
  210. package/dist/upgrader-setup.d.ts.map +1 -1
  211. package/dist/upgrader-setup.js +10 -5
  212. package/dist/upgrader-setup.js.map +1 -1
  213. package/dist/wizard.d.ts +7 -0
  214. package/dist/wizard.d.ts.map +1 -1
  215. package/dist/wizard.js +11 -0
  216. package/dist/wizard.js.map +1 -1
  217. package/dist/wizards/gcp-cost.d.ts +31 -0
  218. package/dist/wizards/gcp-cost.d.ts.map +1 -1
  219. package/dist/wizards/gcp-cost.js +103 -18
  220. package/dist/wizards/gcp-cost.js.map +1 -1
  221. package/dist/wizards/gcp.d.ts.map +1 -1
  222. package/dist/wizards/gcp.js +129 -27
  223. package/dist/wizards/gcp.js.map +1 -1
  224. package/package.json +2 -2
  225. package/src/adapter.ts +6 -0
  226. package/src/admin-domain.test.ts +9 -8
  227. package/src/admin-domain.ts +13 -3
  228. package/src/admin-memory.test.ts +2 -1
  229. package/src/adopt-existing.test.ts +85 -0
  230. package/src/adopt-existing.ts +141 -3
  231. package/src/agent/command.test.ts +49 -1
  232. package/src/agent/command.ts +39 -9
  233. package/src/agent/run.test.ts +19 -0
  234. package/src/agent/run.ts +11 -2
  235. package/src/aws-task-roles.ts +5 -2
  236. package/src/caddy-redirects.docker.test.ts +2 -0
  237. package/src/caddy-redirects.test.ts +4 -1
  238. package/src/caddy-validate.test.ts +7 -1
  239. package/src/caddy.test.ts +39 -1
  240. package/src/caddy.ts +36 -4
  241. package/src/checkpoint-secrets.test.ts +14 -6
  242. package/src/cli-routing.test.ts +1 -1
  243. package/src/cli-routing.ts +1 -1
  244. package/src/cli.ts +71 -5
  245. package/src/cloudsql-tls.test.ts +255 -0
  246. package/src/cloudsql-tls.ts +359 -0
  247. package/src/compose.ts +193 -24
  248. package/src/converge-checkpoint.ts +8 -1
  249. package/src/converge-db-trust.test.ts +237 -0
  250. package/src/converge-db-trust.ts +212 -0
  251. package/src/converge-job-gcp.ts +11 -12
  252. package/src/converge-job-preflight.test.ts +5 -0
  253. package/src/converge-job-preflight.ts +8 -0
  254. package/src/converge-job.test.ts +70 -0
  255. package/src/converge-job.ts +32 -0
  256. package/src/database-tls-builders.test.ts +56 -0
  257. package/src/deployed-release.test.ts +107 -40
  258. package/src/deployed-release.ts +30 -9
  259. package/src/gateway-env-isolation.test.ts +50 -12
  260. package/src/gcp-names.ts +56 -0
  261. package/src/gcp-url-map.test.ts +6 -8
  262. package/src/gcp-url-map.ts +6 -2
  263. package/src/index.test.ts +10 -4
  264. package/src/index.ts +7 -0
  265. package/src/infra-contract.test.ts +7 -3
  266. package/src/infra-contract.ts +45 -1
  267. package/src/install-job.ts +4 -1
  268. package/src/install-state.ts +33 -4
  269. package/src/lifecycle.ts +23 -11
  270. package/src/mcp-auth-proxy-setup.test.ts +305 -0
  271. package/src/mcp-auth-proxy-setup.ts +374 -0
  272. package/src/mcp-iap-stacks.test.ts +1 -1
  273. package/src/media-volume.test.ts +1 -1
  274. package/src/migration-runner.ts +14 -9
  275. package/src/migration-targets.ts +12 -0
  276. package/src/operator-access-stacks.test.ts +1 -1
  277. package/src/operator-access.test.ts +20 -4
  278. package/src/operator-access.ts +14 -0
  279. package/src/pool-budget-stack.ts +15 -0
  280. package/src/pool-budget-stacks.test.ts +39 -14
  281. package/src/public-role-isolation.test.ts +18 -8
  282. package/src/public-role-isolation.ts +31 -17
  283. package/src/release-contract.ts +3 -0
  284. package/src/release-manifest.test.ts +25 -0
  285. package/src/release-manifest.ts +59 -4
  286. package/src/remote-mcp-stack-config.test.ts +19 -9
  287. package/src/remote-mcp.test.ts +252 -57
  288. package/src/remote-mcp.ts +336 -77
  289. package/src/runtime-secrets.test.ts +37 -14
  290. package/src/runtime-secrets.ts +87 -27
  291. package/src/scheduler-setup.test.ts +201 -0
  292. package/src/scheduler-setup.ts +375 -0
  293. package/src/seal-key-rotation.test.ts +2 -2
  294. package/src/seal-key-rotation.ts +25 -25
  295. package/src/self-hosted-backup.test.ts +1 -0
  296. package/src/self-hosted-compose.test.ts +180 -6
  297. package/src/self-hosted-db-tls.test.ts +111 -0
  298. package/src/self-hosted-db-tls.ts +287 -0
  299. package/src/self-hosted-release-resolve.test.ts +71 -0
  300. package/src/self-hosted-release.ts +41 -11
  301. package/src/self-hosted-roles.integration.test.ts +2 -0
  302. package/src/self-hosted-roles.test.ts +87 -3
  303. package/src/self-hosted-roles.ts +101 -3
  304. package/src/self-hosted-scheduler-interval.test.ts +66 -0
  305. package/src/self-hosted-scheduler-interval.ts +79 -0
  306. package/src/self-hosted-start.test.ts +35 -2
  307. package/src/self-hosted-start.ts +20 -2
  308. package/src/self-hosted-upgrade.test.ts +104 -14
  309. package/src/self-hosted-upgrade.ts +123 -31
  310. package/src/stack-contract-parity.test.ts +79 -12
  311. package/src/stack-contract.test.ts +199 -31
  312. package/src/stack-contract.ts +472 -45
  313. package/src/stack-converge-secrets.test.ts +28 -13
  314. package/src/stack-converge.test.ts +203 -28
  315. package/src/stack-converge.ts +92 -30
  316. package/src/staging-database.test.ts +114 -0
  317. package/src/staging-database.ts +148 -0
  318. package/src/state-store.test.ts +2 -1
  319. package/src/upgrade/app-roll.ts +97 -19
  320. package/src/upgrade/converge.ts +249 -19
  321. package/src/upgrade/health.test.ts +63 -25
  322. package/src/upgrade/health.ts +54 -22
  323. package/src/upgrade/image-forms.test.ts +34 -0
  324. package/src/upgrade/image-forms.ts +23 -8
  325. package/src/upgrade/release-images.test.ts +5 -1
  326. package/src/upgrade/release-images.ts +22 -6
  327. package/src/upgrade/upgrade.test.ts +438 -46
  328. package/src/upgrade/upgrade.ts +64 -6
  329. package/src/upgrader-gcp.ts +66 -3
  330. package/src/upgrader-iam-preflight.test.ts +19 -0
  331. package/src/upgrader-iam-preflight.ts +6 -0
  332. package/src/upgrader-job.test.ts +101 -27
  333. package/src/upgrader-job.ts +27 -14
  334. package/src/upgrader-records.test.ts +97 -12
  335. package/src/upgrader-records.ts +28 -11
  336. package/src/upgrader-setup.test.ts +2 -0
  337. package/src/upgrader-setup.ts +10 -4
  338. package/src/wizard.ts +19 -0
  339. package/src/wizards/gcp-cost.test.ts +103 -0
  340. package/src/wizards/gcp-cost.ts +125 -18
  341. package/src/wizards/gcp.ts +164 -22
  342. package/stacks/aws/Pulumi.yaml +1 -1
  343. package/stacks/aws/index.ts +72 -14
  344. package/stacks/azure/index.ts +108 -21
  345. package/stacks/gcp/Pulumi.yaml +1 -1
  346. package/stacks/gcp/README.md +1 -0
  347. package/stacks/gcp/index.ts +133 -24
  348. package/stacks/gcp-firebase/Pulumi.yaml +1 -1
  349. package/stacks/gcp-firebase/index.ts +212 -34
  350. package/stacks/self-hosted/Pulumi.yaml +3 -0
  351. package/stacks/self-hosted/README.md +6 -1
  352. package/stacks/self-hosted/index.ts +40 -5
@@ -27,27 +27,33 @@ import {
27
27
  gcpBucketName,
28
28
  gcpSecretId,
29
29
  MCP_IAP_SERVICE_ACCOUNT_ID,
30
+ mcpAuthProxyServiceAccountId,
30
31
  runServiceAccountId,
31
32
  staticPublisherServiceAccountId,
32
33
  } from "../../dist/gcp-names.js";
33
34
  import { createSiteUrlMap } from "../../dist/gcp-url-map.js";
34
35
  import {
36
+ DEFAULT_ADMIN_MAX_INSTANCES,
35
37
  DEFAULT_GATEWAY_MAX_INSTANCES,
36
38
  DEFAULT_MAX_CONNECTIONS,
39
+ DEFAULT_STAGING_GATEWAY_MAX_INSTANCES,
37
40
  stackPoolBudget,
38
41
  } from "../../dist/pool-budget-stack.js";
39
- import { mcpArmorRuleArgs } from "../../dist/remote-mcp-edge.js";
40
42
  import {
41
43
  ADMIN_MEMORY_DEFAULT,
42
44
  adminEnvContract,
43
45
  adminMediaVolume,
44
46
  adminMediaVolumeTemplate,
45
47
  CLOUD_RUN_IGNORE_CHANGES,
48
+ CLOUD_SQL_PSA_CONNECTION_TYPE,
49
+ CLOUD_SQL_SERVER_CA_MODE,
50
+ CLOUD_SQL_SSL_MODE,
46
51
  type CloudRunEnvVar,
47
52
  type CloudRunSlug,
53
+ cloudSqlDnsZoneName,
54
+ cloudSqlPrivateDnsName,
48
55
  databaseUrls,
49
56
  defaultStagingHost,
50
- GATEWAY_TIMEOUT_SECONDS,
51
57
  gatewayEnvContract,
52
58
  REMOTE_MCP_IDENTITY_CONFIG,
53
59
  type RuntimeSecret,
@@ -115,7 +121,10 @@ const adminMemory = cfg.get("adminMemory") ?? ADMIN_MEMORY_DEFAULT;
115
121
  // against the original 25-slot Postgres default — connection exhaustion
116
122
  // took the admin offline. v0.2.49 bakes the post-incident shape so fresh
117
123
  // installs don't trip the same wall.
118
- const adminMaxInstances = Number.parseInt(cfg.get("adminMaxInstances") ?? "5", 10);
124
+ const adminMaxInstances = Number.parseInt(
125
+ cfg.get("adminMaxInstances") ?? String(DEFAULT_ADMIN_MAX_INSTANCES),
126
+ 10,
127
+ );
119
128
  const gatewayMinInstances = Number.parseInt(cfg.get("gatewayMinInstances") ?? "0", 10);
120
129
  // #1254 — the gateway's scale-out is part of the connection budget: each
121
130
  // instance holds a cms_public pool.
@@ -133,6 +142,8 @@ const poolBudget = stackPoolBudget("gcp", {
133
142
  maxConnections,
134
143
  adminMaxInstances,
135
144
  gatewayMaxInstances,
145
+ // #1329 — the staging gateway (P3b-2) is budgeted from this release on.
146
+ stagingGatewayMaxInstances: DEFAULT_STAGING_GATEWAY_MAX_INSTANCES,
136
147
  });
137
148
  const wafAdaptiveProtection = cfg.getBoolean("wafAdaptiveProtection") ?? false;
138
149
  const backupRetentionDays = Number.parseInt(cfg.get("backupRetentionDays") ?? "7", 10);
@@ -277,6 +288,8 @@ const runtimeSecretIds: Record<RuntimeSecret, pulumi.Input<string>> = {
277
288
  "tool-approval-secret": gcpSecretId(env, "tool-approval-secret"),
278
289
  "staging-gate-secret": gcpSecretId(env, "staging-gate-secret"),
279
290
  "public-role-password": gcpSecretId(env, "public-role-password"),
291
+ // #1329 — the staging gateway's login, never the live one's.
292
+ "public-staging-role-password": gcpSecretId(env, "public-staging-role-password"),
280
293
  // #914 / #806 — the Owner-set Google sign-in client (a placeholder until
281
294
  // then; IAP login, IAP programmatic access and the remote-MCP broker) and
282
295
  // the broker's seal key, both CLI-generated.
@@ -293,6 +306,14 @@ const publicRolePassword = pulumi.secret(
293
306
  { provider: gcpProvider },
294
307
  ).secretData,
295
308
  );
309
+ // #1329 — public_staging_role's own password (CLI-generated like the one
310
+ // above): the staging gateway's only login, on cms_public_staging only.
311
+ const publicStagingRolePassword = pulumi.secret(
312
+ gcp.secretmanager.getSecretVersionOutput(
313
+ { project, secret: gcpSecretId(env, "public-staging-role-password") },
314
+ { provider: gcpProvider },
315
+ ).secretData,
316
+ );
296
317
 
297
318
  // =========================================================================
298
319
  // Tier 4 — Cloud SQL Postgres (private IP only; HA + retention configurable)
@@ -331,6 +352,11 @@ const sqlInstance = new gcp.sql.DatabaseInstance(
331
352
  ipConfiguration: {
332
353
  ipv4Enabled: false,
333
354
  privateNetwork: network.id,
355
+ // #1338 — the shared CA names the instance's DNS name in its server
356
+ // certificate, so every client verifies it (sslmode=verify-full);
357
+ // unencrypted connections are refused outright.
358
+ serverCaMode: CLOUD_SQL_SERVER_CA_MODE,
359
+ sslMode: CLOUD_SQL_SSL_MODE,
334
360
  },
335
361
  deletionProtectionEnabled: deletionProtection,
336
362
  },
@@ -362,6 +388,14 @@ const pgPublicUser = new gcp.sql.User(
362
388
  { instance: sqlInstance.name, name: "public_role", password: publicRolePassword },
363
389
  opts,
364
390
  );
391
+ // #1329 — the staging gateway's login: an Admin API user like public_role,
392
+ // so the same membership revoke (public-role-isolation.ts) and the same
393
+ // audit apply; migration 0530 gives it CONNECT on cms_public_staging only.
394
+ new gcp.sql.User(
395
+ `${namePrefix}-pg-public-staging`,
396
+ { instance: sqlInstance.name, name: "public_staging_role", password: publicStagingRolePassword },
397
+ opts,
398
+ );
365
399
 
366
400
  const cmsAdminDb = new gcp.sql.Database(
367
401
  `${namePrefix}-cms-admin-db`,
@@ -373,11 +407,58 @@ const cmsPublicDb = new gcp.sql.Database(
373
407
  { instance: sqlInstance.name, name: "cms_public" },
374
408
  opts,
375
409
  );
410
+ // #1329 — staging's own data: the twin of cms_public on the same instance
411
+ // (no extra cost), reached by the staging gateway only.
412
+ const cmsPublicStagingDb = new gcp.sql.Database(
413
+ `${namePrefix}-cms-public-staging-db`,
414
+ { instance: sqlInstance.name, name: "cms_public_staging" },
415
+ opts,
416
+ );
417
+
418
+ // #1338 — the instance's DNS name, resolved to its private IP by a private
419
+ // zone in the VPC (Cloud SQL assigns the name, it does not resolve it).
420
+ // Every client dials this name with sslmode=verify-full; the certificate
421
+ // names no IP. `cms-provision upgrade` converges the same zone and record
422
+ // through gcloud (cloudsql-tls.ts); the installer adopts them (#1079).
423
+ const sqlDnsName = sqlInstance.dnsNames.apply((names) => {
424
+ const name = cloudSqlPrivateDnsName(names);
425
+ if (!name) {
426
+ throw new Error(
427
+ `Cloud SQL instance has no ${CLOUD_SQL_PSA_CONNECTION_TYPE} DNS name; it needs the shared server CA (${CLOUD_SQL_SERVER_CA_MODE}) for verify-full connections (#1338)`,
428
+ );
429
+ }
430
+ return name;
431
+ });
432
+ const sqlDnsZone = new gcp.dns.ManagedZone(
433
+ `${namePrefix}-pg-dns`,
434
+ {
435
+ name: cloudSqlDnsZoneName(env),
436
+ dnsName: pulumi.interpolate`${sqlDnsName}.`,
437
+ visibility: "private",
438
+ privateVisibilityConfig: { networks: [{ networkUrl: network.id }] },
439
+ description: `Caelo ${env}: the Cloud SQL instance's DNS name inside the VPC (#1338)`,
440
+ },
441
+ opts,
442
+ );
443
+ const sqlDnsRecord = new gcp.dns.RecordSet(
444
+ `${namePrefix}-pg-dns-a`,
445
+ {
446
+ // Literal names, not the zone's outputs: the installer can then adopt
447
+ // a record an upgrade created (adopt-existing.ts) from the preview.
448
+ managedZone: cloudSqlDnsZoneName(env),
449
+ name: pulumi.interpolate`${sqlDnsName}.`,
450
+ type: "A",
451
+ ttl: 300,
452
+ rrdatas: [sqlInstance.privateIpAddress],
453
+ },
454
+ { ...opts, dependsOn: [sqlDnsZone] },
455
+ );
376
456
 
377
457
  // Password-less connection URLs (stack-contract.ts databaseUrls); the
378
458
  // services get the password as a Secret Manager reference
379
- // (SERVICE_SECRET_ENV), so no revision ever carries it.
380
- const dbUrls = sqlInstance.privateIpAddress.apply(databaseUrls);
459
+ // (SERVICE_SECRET_ENV), so no revision ever carries it. Tied to the record
460
+ // so no revision boots before its database host resolves.
461
+ const dbUrls = pulumi.all([sqlDnsName, sqlDnsRecord.id]).apply(([host]) => databaseUrls(host));
381
462
 
382
463
  // Reference pgPublicUser so Pulumi knows it's part of the dependency
383
464
  // graph (Cloud Run env-var deps don't see this directly).
@@ -475,9 +556,24 @@ const gatewaySa = new gcp.serviceaccount.Account(
475
556
  },
476
557
  opts,
477
558
  );
559
+ // #1328 — the MCP-Auth-Proxy's own SA and (below) its secretAccessor on its
560
+ // two secrets, nothing else. The proxy's service, NEG, backend and Cloud
561
+ // Armor policy are the CLI's (remote-mcp.ts ensureRemoteMcpEdge, after the
562
+ // first `up`), like the jobs: the converge creates the same on existing
563
+ // installs, and the URL map's path rules are the CLI's already.
564
+ const mcpAuthProxySa = new gcp.serviceaccount.Account(
565
+ `${namePrefix}-mcp-auth-proxy-sa`,
566
+ {
567
+ accountId: mcpAuthProxyServiceAccountId(env),
568
+ displayName: `Caelo ${env} MCP-Auth-Proxy`,
569
+ createIgnoreAlreadyExists: true,
570
+ },
571
+ opts,
572
+ );
478
573
  const serviceSa: Record<CloudRunSlug, gcp.serviceaccount.Account> = {
479
574
  admin: runSa,
480
575
  gateway: gatewaySa,
576
+ "mcp-auth-proxy": mcpAuthProxySa,
481
577
  };
482
578
 
483
579
  // secretAccessor for each service's SA on exactly the secrets its env reads.
@@ -486,6 +582,7 @@ const serviceSa: Record<CloudRunSlug, gcp.serviceaccount.Account> = {
486
582
  const secretBindings: Record<CloudRunSlug, gcp.secretmanager.SecretIamMember[]> = {
487
583
  admin: [],
488
584
  gateway: [],
585
+ "mcp-auth-proxy": [],
489
586
  };
490
587
  for (const binding of runtimeSecretBindings()) {
491
588
  secretBindings[binding.service].push(
@@ -662,7 +759,8 @@ function imageTag(service: string): pulumi.Output<string> {
662
759
  }
663
760
 
664
761
  interface CloudRunArgs {
665
- readonly serviceName: "admin" | "gateway";
762
+ /** The MCP-Auth-Proxy is CLI-owned on this stack (see mcpAuthProxySa). */
763
+ readonly serviceName: Exclude<CloudRunSlug, "mcp-auth-proxy">;
666
764
  readonly minInstances: number;
667
765
  readonly maxInstances: number;
668
766
  readonly memory: string;
@@ -670,8 +768,7 @@ interface CloudRunArgs {
670
768
  * Per-request timeout. Cloud Run's default is 300s (5min), which is too
671
769
  * short for the admin's SSE chat-stream — a multi-tool compose-page session
672
770
  * regularly runs 5–15 min. Pass an explicit "<n>s" Pulumi-style duration
673
- * string. The gateway gets the same (#806): it proxies remote-MCP chat
674
- * streams to the admin.
771
+ * string.
675
772
  */
676
773
  readonly timeout?: string;
677
774
  /**
@@ -702,6 +799,8 @@ const envContractInputs = {
702
799
  admin: dbUrls.admin,
703
800
  publicAdmin: dbUrls.publicAdmin,
704
801
  public: dbUrls.public,
802
+ publicStagingAdmin: dbUrls.publicStagingAdmin,
803
+ publicStaging: dbUrls.publicStaging,
705
804
  },
706
805
  } as const;
707
806
 
@@ -776,6 +875,7 @@ function cloudRunService(args: CloudRunArgs): gcp.cloudrunv2.Service {
776
875
  pgAdminUser,
777
876
  cmsAdminDb,
778
877
  cmsPublicDb,
878
+ cmsPublicStagingDb,
779
879
  // The env contract names the buckets as strings; keep them ordered
780
880
  // before the services that use them.
781
881
  mediaBucket,
@@ -816,18 +916,12 @@ const gatewaySvc = cloudRunService({
816
916
  minInstances: gatewayMinInstances,
817
917
  maxInstances: gatewayMaxInstances,
818
918
  memory: "512Mi",
819
- // #806 — remote MCP: chat turns stream through the gateway for minutes,
820
- // so it gets the admin's 3600 s instead of Cloud Run's 300 s default
821
- // (stack-contract.ts GATEWAY_TIMEOUT_SECONDS). The LB in front imposes no
822
- // shorter limit on serverless NEG backends.
823
- timeout: `${GATEWAY_TIMEOUT_SECONDS}s`,
919
+ // Visitor requests only (#1328 moved remote MCP's long streams to the
920
+ // MCP-Auth-Proxy): Cloud Run's default.
921
+ timeout: "300s",
824
922
  // public_role on cms_public only: no cms_admin login of any role
825
923
  // (#613, #635, CLAUDE.md §2).
826
- contractEnv: [
827
- ...gatewayEnvContract(envContractInputs),
828
- ...remoteMcpEnv.gateway,
829
- ...poolBudget.env.gateway,
830
- ],
924
+ contractEnv: [...gatewayEnvContract(envContractInputs), ...poolBudget.env.gateway],
831
925
  });
832
926
 
833
927
  // =========================================================================
@@ -838,6 +932,9 @@ const gatewaySvc = cloudRunService({
838
932
  // admin.caelo-cms.com. Three backends routed by Host header / path:
839
933
  // - host=caelo-cms.com, default → static bucket (Cloud CDN)
840
934
  // - host=caelo-cms.com, path=/api/* → gateway Cloud Run (Cloud Armor)
935
+ // - host=caelo-cms.com, path=/api/mcp/*, /.well-known/oauth-*
936
+ // → MCP-Auth-Proxy Cloud Run (its own
937
+ // Cloud Armor; CLI-owned, #1328)
841
938
  // - host=admin.caelo-cms.com, default → admin Cloud Run (IAP-gated)
842
939
  //
843
940
  // CLAUDE.md §11.B Tier 2: admin behind cloud-native identity proxy. IAP
@@ -860,12 +957,10 @@ const wafPolicy = new gcp.compute.SecurityPolicy(
860
957
  {
861
958
  description: `Caelo ${env} Cloud Armor — rate limit + OWASP`,
862
959
  rules: [
863
- // #806 — remote MCP (/api/mcp/*): a per-IP throttle sized for agent
864
- // traffic behind shared connector IPs, evaluated first; below it the
865
- // rule allows, so the OWASP packs (MCP bodies carry HTML) and the
866
- // general ban below do not apply there. src/remote-mcp-edge.ts says
867
- // why; `cms-provision upgrade` adds the same rule to existing installs.
868
- mcpArmorRuleArgs(),
960
+ // #1328 — no remote-MCP rule here any more: the URL map sends
961
+ // /api/mcp/* to the MCP-Auth-Proxy's backend, whose own policy carries
962
+ // it (remote-mcp-edge.ts, created by the CLI; `upgrade` drops the old
963
+ // rule from this policy).
869
964
  // Rate limit per source IP — 100 req / min sliding window.
870
965
  {
871
966
  action: "rate_based_ban",
@@ -1095,6 +1190,18 @@ new gcp.iap.WebBackendServiceIamMember(
1095
1190
  // (packages/provisioning/src/capture-job-setup.ts), for the same reason as
1096
1191
  // the audit job above.
1097
1192
 
1193
+ // =========================================================================
1194
+ // Scheduler tick — deliberately NOT here
1195
+ // =========================================================================
1196
+ //
1197
+ // #1140 — one Cloud Scheduler job starts a Cloud Workflows execution every
1198
+ // `schedulerIntervalMinutes` (1–15, default 5); the workflow signs an IAP
1199
+ // credential as the scheduler's own service account and POSTs the admin's
1200
+ // /api/internal/scheduler/tick, where the admin runs its periodic work and
1201
+ // plugin workers from its due-table. The CLI owns the account, its grants,
1202
+ // the workflow and the job (packages/provisioning/src/scheduler-setup.ts),
1203
+ // for the same reason as the audit job above.
1204
+
1098
1205
  // =========================================================================
1099
1206
  // Operator access — deliberately NOT here
1100
1207
  // =========================================================================
@@ -1265,6 +1372,7 @@ const out: CloudAdapterOutputs = {
1265
1372
  // Password-less — the password lives only in Secret Manager.
1266
1373
  adminDatabaseUrl: dbUrls.admin as unknown as string,
1267
1374
  publicDatabaseUrl: dbUrls.public as unknown as string,
1375
+ publicStagingDatabaseUrl: dbUrls.publicStaging as unknown as string,
1268
1376
  mediaStorageUrl: pulumi.interpolate`gs://${mediaBucket.name}` as unknown as string,
1269
1377
  mediaCdnBaseUrl: pulumi.interpolate`https://${domain}/media` as unknown as string,
1270
1378
  bootstrapUrl:
@@ -1278,6 +1386,7 @@ const out: CloudAdapterOutputs = {
1278
1386
 
1279
1387
  export const adminDatabaseUrlOut = out.adminDatabaseUrl;
1280
1388
  export const publicDatabaseUrlOut = out.publicDatabaseUrl;
1389
+ export const publicStagingDatabaseUrlOut = out.publicStagingDatabaseUrl;
1281
1390
  export const mediaStorageUrlOut = out.mediaStorageUrl;
1282
1391
  export const mediaCdnBaseUrlOut = out.mediaCdnBaseUrl;
1283
1392
  export const bootstrapUrlOut = out.bootstrapUrl;
@@ -58,7 +58,7 @@ config:
58
58
  description: Admin Cloud Run memory. 2Gi leaves room for the Lighthouse quality audit next to editor requests; billed only while an instance runs.
59
59
  caelo-gcp-firebase:adminMaxInstances:
60
60
  type: string
61
- default: "5"
61
+ default: "4"
62
62
  description: Admin Cloud Run max instances.
63
63
  caelo-gcp-firebase:maxConnections:
64
64
  type: string