@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.
- package/dist/adapter.d.ts +6 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/admin-domain.d.ts +10 -1
- package/dist/admin-domain.d.ts.map +1 -1
- package/dist/admin-domain.js +13 -3
- package/dist/admin-domain.js.map +1 -1
- package/dist/adopt-existing.d.ts +12 -3
- package/dist/adopt-existing.d.ts.map +1 -1
- package/dist/adopt-existing.js +143 -0
- package/dist/adopt-existing.js.map +1 -1
- package/dist/agent/command.d.ts +23 -0
- package/dist/agent/command.d.ts.map +1 -1
- package/dist/agent/command.js +32 -9
- package/dist/agent/command.js.map +1 -1
- package/dist/agent/run.d.ts +2 -0
- package/dist/agent/run.d.ts.map +1 -1
- package/dist/agent/run.js +5 -1
- package/dist/agent/run.js.map +1 -1
- package/dist/agent-db.js +69 -10
- package/dist/aws-task-roles.d.ts +4 -2
- package/dist/aws-task-roles.d.ts.map +1 -1
- package/dist/aws-task-roles.js +4 -1
- package/dist/aws-task-roles.js.map +1 -1
- package/dist/caddy.d.ts +21 -4
- package/dist/caddy.d.ts.map +1 -1
- package/dist/caddy.js +27 -3
- package/dist/caddy.js.map +1 -1
- package/dist/cli-routing.js +1 -1
- package/dist/cli-routing.js.map +1 -1
- package/dist/cli.js +68 -7
- package/dist/cli.js.map +1 -1
- package/dist/cloudsql-tls.d.ts +93 -0
- package/dist/cloudsql-tls.d.ts.map +1 -0
- package/dist/cloudsql-tls.js +295 -0
- package/dist/cloudsql-tls.js.map +1 -0
- package/dist/compose.d.ts +43 -6
- package/dist/compose.d.ts.map +1 -1
- package/dist/compose.js +148 -23
- package/dist/compose.js.map +1 -1
- package/dist/converge-checkpoint.d.ts +1 -0
- package/dist/converge-checkpoint.d.ts.map +1 -1
- package/dist/converge-checkpoint.js +8 -1
- package/dist/converge-checkpoint.js.map +1 -1
- package/dist/converge-db-trust.d.ts +44 -0
- package/dist/converge-db-trust.d.ts.map +1 -0
- package/dist/converge-db-trust.js +158 -0
- package/dist/converge-db-trust.js.map +1 -0
- package/dist/converge-job-gcp.d.ts +5 -2
- package/dist/converge-job-gcp.d.ts.map +1 -1
- package/dist/converge-job-gcp.js +11 -13
- package/dist/converge-job-gcp.js.map +1 -1
- package/dist/converge-job-preflight.d.ts.map +1 -1
- package/dist/converge-job-preflight.js +8 -0
- package/dist/converge-job-preflight.js.map +1 -1
- package/dist/converge-job.d.ts +17 -0
- package/dist/converge-job.d.ts.map +1 -1
- package/dist/converge-job.js +12 -0
- package/dist/converge-job.js.map +1 -1
- package/dist/deployed-release.d.ts +4 -1
- package/dist/deployed-release.d.ts.map +1 -1
- package/dist/deployed-release.js +18 -8
- package/dist/deployed-release.js.map +1 -1
- package/dist/gcp-names.d.ts +34 -0
- package/dist/gcp-names.d.ts.map +1 -1
- package/dist/gcp-names.js +45 -0
- package/dist/gcp-names.js.map +1 -1
- package/dist/gcp-url-map.d.ts.map +1 -1
- package/dist/gcp-url-map.js +6 -2
- package/dist/gcp-url-map.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/infra-contract.d.ts +1 -1
- package/dist/infra-contract.d.ts.map +1 -1
- package/dist/infra-contract.js +45 -1
- package/dist/infra-contract.js.map +1 -1
- package/dist/install-job.d.ts +4 -2
- package/dist/install-job.d.ts.map +1 -1
- package/dist/install-job.js +4 -1
- package/dist/install-job.js.map +1 -1
- package/dist/install-state.d.ts +13 -0
- package/dist/install-state.d.ts.map +1 -1
- package/dist/install-state.js +17 -4
- package/dist/install-state.js.map +1 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +20 -8
- package/dist/lifecycle.js.map +1 -1
- package/dist/mcp-auth-proxy-setup.d.ts +48 -0
- package/dist/mcp-auth-proxy-setup.d.ts.map +1 -0
- package/dist/mcp-auth-proxy-setup.js +280 -0
- package/dist/mcp-auth-proxy-setup.js.map +1 -0
- package/dist/migration-runner.d.ts.map +1 -1
- package/dist/migration-runner.js +8 -3
- package/dist/migration-runner.js.map +1 -1
- package/dist/migration-targets.d.ts +11 -0
- package/dist/migration-targets.d.ts.map +1 -0
- package/dist/migration-targets.js +12 -0
- package/dist/migration-targets.js.map +1 -0
- package/dist/operator-access.d.ts +10 -0
- package/dist/operator-access.d.ts.map +1 -1
- package/dist/operator-access.js +5 -0
- package/dist/operator-access.js.map +1 -1
- package/dist/pool-budget-stack.d.ts +13 -1
- package/dist/pool-budget-stack.d.ts.map +1 -1
- package/dist/pool-budget-stack.js +11 -1
- package/dist/pool-budget-stack.js.map +1 -1
- package/dist/public-role-isolation.d.ts +7 -3
- package/dist/public-role-isolation.d.ts.map +1 -1
- package/dist/public-role-isolation.js +25 -13
- package/dist/public-role-isolation.js.map +1 -1
- package/dist/release-contract.d.ts.map +1 -1
- package/dist/release-contract.js +3 -0
- package/dist/release-contract.js.map +1 -1
- package/dist/release-manifest.d.ts +25 -1
- package/dist/release-manifest.d.ts.map +1 -1
- package/dist/release-manifest.js +36 -3
- package/dist/release-manifest.js.map +1 -1
- package/dist/remote-mcp.d.ts +55 -18
- package/dist/remote-mcp.d.ts.map +1 -1
- package/dist/remote-mcp.js +307 -77
- package/dist/remote-mcp.js.map +1 -1
- package/dist/runtime-secrets.d.ts +11 -0
- package/dist/runtime-secrets.d.ts.map +1 -1
- package/dist/runtime-secrets.js +40 -25
- package/dist/runtime-secrets.js.map +1 -1
- package/dist/scheduler-setup.d.ts +75 -0
- package/dist/scheduler-setup.d.ts.map +1 -0
- package/dist/scheduler-setup.js +331 -0
- package/dist/scheduler-setup.js.map +1 -0
- package/dist/seal-key-rotation.d.ts +7 -7
- package/dist/seal-key-rotation.d.ts.map +1 -1
- package/dist/seal-key-rotation.js +22 -22
- package/dist/seal-key-rotation.js.map +1 -1
- package/dist/self-hosted-db-tls.d.ts +37 -0
- package/dist/self-hosted-db-tls.d.ts.map +1 -0
- package/dist/self-hosted-db-tls.js +220 -0
- package/dist/self-hosted-db-tls.js.map +1 -0
- package/dist/self-hosted-release.d.ts +3 -1
- package/dist/self-hosted-release.d.ts.map +1 -1
- package/dist/self-hosted-release.js +33 -9
- package/dist/self-hosted-release.js.map +1 -1
- package/dist/self-hosted-roles.d.ts +43 -2
- package/dist/self-hosted-roles.d.ts.map +1 -1
- package/dist/self-hosted-roles.js +87 -1
- package/dist/self-hosted-roles.js.map +1 -1
- package/dist/self-hosted-scheduler-interval.d.ts +21 -0
- package/dist/self-hosted-scheduler-interval.d.ts.map +1 -0
- package/dist/self-hosted-scheduler-interval.js +68 -0
- package/dist/self-hosted-scheduler-interval.js.map +1 -0
- package/dist/self-hosted-start.d.ts +0 -21
- package/dist/self-hosted-start.d.ts.map +1 -1
- package/dist/self-hosted-start.js +39 -1
- package/dist/self-hosted-start.js.map +1 -1
- package/dist/self-hosted-upgrade.d.ts +19 -7
- package/dist/self-hosted-upgrade.d.ts.map +1 -1
- package/dist/self-hosted-upgrade.js +78 -25
- package/dist/self-hosted-upgrade.js.map +1 -1
- package/dist/stack-contract.d.ts +234 -28
- package/dist/stack-contract.d.ts.map +1 -1
- package/dist/stack-contract.js +397 -39
- package/dist/stack-contract.js.map +1 -1
- package/dist/stack-converge.d.ts +31 -0
- package/dist/stack-converge.d.ts.map +1 -1
- package/dist/stack-converge.js +71 -30
- package/dist/stack-converge.js.map +1 -1
- package/dist/staging-database.d.ts +22 -0
- package/dist/staging-database.d.ts.map +1 -0
- package/dist/staging-database.js +117 -0
- package/dist/staging-database.js.map +1 -0
- package/dist/upgrade/app-roll.d.ts +25 -4
- package/dist/upgrade/app-roll.d.ts.map +1 -1
- package/dist/upgrade/app-roll.js +63 -17
- package/dist/upgrade/app-roll.js.map +1 -1
- package/dist/upgrade/converge.d.ts +5 -0
- package/dist/upgrade/converge.d.ts.map +1 -1
- package/dist/upgrade/converge.js +207 -20
- package/dist/upgrade/converge.js.map +1 -1
- package/dist/upgrade/health.d.ts +31 -7
- package/dist/upgrade/health.d.ts.map +1 -1
- package/dist/upgrade/health.js +41 -17
- package/dist/upgrade/health.js.map +1 -1
- package/dist/upgrade/image-forms.d.ts +1 -1
- package/dist/upgrade/image-forms.d.ts.map +1 -1
- package/dist/upgrade/image-forms.js +24 -7
- package/dist/upgrade/image-forms.js.map +1 -1
- package/dist/upgrade/release-images.d.ts +12 -3
- package/dist/upgrade/release-images.d.ts.map +1 -1
- package/dist/upgrade/release-images.js +13 -4
- package/dist/upgrade/release-images.js.map +1 -1
- package/dist/upgrade/upgrade.d.ts +19 -3
- package/dist/upgrade/upgrade.d.ts.map +1 -1
- package/dist/upgrade/upgrade.js +37 -2
- package/dist/upgrade/upgrade.js.map +1 -1
- package/dist/upgrader-gcp.d.ts +13 -0
- package/dist/upgrader-gcp.d.ts.map +1 -1
- package/dist/upgrader-gcp.js +50 -1
- package/dist/upgrader-gcp.js.map +1 -1
- package/dist/upgrader-iam-preflight.d.ts.map +1 -1
- package/dist/upgrader-iam-preflight.js +6 -1
- package/dist/upgrader-iam-preflight.js.map +1 -1
- package/dist/upgrader-job.d.ts +1 -1
- package/dist/upgrader-job.d.ts.map +1 -1
- package/dist/upgrader-job.js +20 -14
- package/dist/upgrader-job.js.map +1 -1
- package/dist/upgrader-records.d.ts +1 -1
- package/dist/upgrader-records.d.ts.map +1 -1
- package/dist/upgrader-records.js +26 -7
- package/dist/upgrader-records.js.map +1 -1
- package/dist/upgrader-setup.d.ts.map +1 -1
- package/dist/upgrader-setup.js +10 -5
- package/dist/upgrader-setup.js.map +1 -1
- package/dist/wizard.d.ts +7 -0
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +11 -0
- package/dist/wizard.js.map +1 -1
- package/dist/wizards/gcp-cost.d.ts +31 -0
- package/dist/wizards/gcp-cost.d.ts.map +1 -1
- package/dist/wizards/gcp-cost.js +103 -18
- package/dist/wizards/gcp-cost.js.map +1 -1
- package/dist/wizards/gcp.d.ts.map +1 -1
- package/dist/wizards/gcp.js +129 -27
- package/dist/wizards/gcp.js.map +1 -1
- package/package.json +2 -2
- package/src/adapter.ts +6 -0
- package/src/admin-domain.test.ts +9 -8
- package/src/admin-domain.ts +13 -3
- package/src/admin-memory.test.ts +2 -1
- package/src/adopt-existing.test.ts +85 -0
- package/src/adopt-existing.ts +141 -3
- package/src/agent/command.test.ts +49 -1
- package/src/agent/command.ts +39 -9
- package/src/agent/run.test.ts +19 -0
- package/src/agent/run.ts +11 -2
- package/src/aws-task-roles.ts +5 -2
- package/src/caddy-redirects.docker.test.ts +2 -0
- package/src/caddy-redirects.test.ts +4 -1
- package/src/caddy-validate.test.ts +7 -1
- package/src/caddy.test.ts +39 -1
- package/src/caddy.ts +36 -4
- package/src/checkpoint-secrets.test.ts +14 -6
- package/src/cli-routing.test.ts +1 -1
- package/src/cli-routing.ts +1 -1
- package/src/cli.ts +71 -5
- package/src/cloudsql-tls.test.ts +255 -0
- package/src/cloudsql-tls.ts +359 -0
- package/src/compose.ts +193 -24
- package/src/converge-checkpoint.ts +8 -1
- package/src/converge-db-trust.test.ts +237 -0
- package/src/converge-db-trust.ts +212 -0
- package/src/converge-job-gcp.ts +11 -12
- package/src/converge-job-preflight.test.ts +5 -0
- package/src/converge-job-preflight.ts +8 -0
- package/src/converge-job.test.ts +70 -0
- package/src/converge-job.ts +32 -0
- package/src/database-tls-builders.test.ts +56 -0
- package/src/deployed-release.test.ts +107 -40
- package/src/deployed-release.ts +30 -9
- package/src/gateway-env-isolation.test.ts +50 -12
- package/src/gcp-names.ts +56 -0
- package/src/gcp-url-map.test.ts +6 -8
- package/src/gcp-url-map.ts +6 -2
- package/src/index.test.ts +10 -4
- package/src/index.ts +7 -0
- package/src/infra-contract.test.ts +7 -3
- package/src/infra-contract.ts +45 -1
- package/src/install-job.ts +4 -1
- package/src/install-state.ts +33 -4
- package/src/lifecycle.ts +23 -11
- package/src/mcp-auth-proxy-setup.test.ts +305 -0
- package/src/mcp-auth-proxy-setup.ts +374 -0
- package/src/mcp-iap-stacks.test.ts +1 -1
- package/src/media-volume.test.ts +1 -1
- package/src/migration-runner.ts +14 -9
- package/src/migration-targets.ts +12 -0
- package/src/operator-access-stacks.test.ts +1 -1
- package/src/operator-access.test.ts +20 -4
- package/src/operator-access.ts +14 -0
- package/src/pool-budget-stack.ts +15 -0
- package/src/pool-budget-stacks.test.ts +39 -14
- package/src/public-role-isolation.test.ts +18 -8
- package/src/public-role-isolation.ts +31 -17
- package/src/release-contract.ts +3 -0
- package/src/release-manifest.test.ts +25 -0
- package/src/release-manifest.ts +59 -4
- package/src/remote-mcp-stack-config.test.ts +19 -9
- package/src/remote-mcp.test.ts +252 -57
- package/src/remote-mcp.ts +336 -77
- package/src/runtime-secrets.test.ts +37 -14
- package/src/runtime-secrets.ts +87 -27
- package/src/scheduler-setup.test.ts +201 -0
- package/src/scheduler-setup.ts +375 -0
- package/src/seal-key-rotation.test.ts +2 -2
- package/src/seal-key-rotation.ts +25 -25
- package/src/self-hosted-backup.test.ts +1 -0
- package/src/self-hosted-compose.test.ts +180 -6
- package/src/self-hosted-db-tls.test.ts +111 -0
- package/src/self-hosted-db-tls.ts +287 -0
- package/src/self-hosted-release-resolve.test.ts +71 -0
- package/src/self-hosted-release.ts +41 -11
- package/src/self-hosted-roles.integration.test.ts +2 -0
- package/src/self-hosted-roles.test.ts +87 -3
- package/src/self-hosted-roles.ts +101 -3
- package/src/self-hosted-scheduler-interval.test.ts +66 -0
- package/src/self-hosted-scheduler-interval.ts +79 -0
- package/src/self-hosted-start.test.ts +35 -2
- package/src/self-hosted-start.ts +20 -2
- package/src/self-hosted-upgrade.test.ts +104 -14
- package/src/self-hosted-upgrade.ts +123 -31
- package/src/stack-contract-parity.test.ts +79 -12
- package/src/stack-contract.test.ts +199 -31
- package/src/stack-contract.ts +472 -45
- package/src/stack-converge-secrets.test.ts +28 -13
- package/src/stack-converge.test.ts +203 -28
- package/src/stack-converge.ts +92 -30
- package/src/staging-database.test.ts +114 -0
- package/src/staging-database.ts +148 -0
- package/src/state-store.test.ts +2 -1
- package/src/upgrade/app-roll.ts +97 -19
- package/src/upgrade/converge.ts +249 -19
- package/src/upgrade/health.test.ts +63 -25
- package/src/upgrade/health.ts +54 -22
- package/src/upgrade/image-forms.test.ts +34 -0
- package/src/upgrade/image-forms.ts +23 -8
- package/src/upgrade/release-images.test.ts +5 -1
- package/src/upgrade/release-images.ts +22 -6
- package/src/upgrade/upgrade.test.ts +438 -46
- package/src/upgrade/upgrade.ts +64 -6
- package/src/upgrader-gcp.ts +66 -3
- package/src/upgrader-iam-preflight.test.ts +19 -0
- package/src/upgrader-iam-preflight.ts +6 -0
- package/src/upgrader-job.test.ts +101 -27
- package/src/upgrader-job.ts +27 -14
- package/src/upgrader-records.test.ts +97 -12
- package/src/upgrader-records.ts +28 -11
- package/src/upgrader-setup.test.ts +2 -0
- package/src/upgrader-setup.ts +10 -4
- package/src/wizard.ts +19 -0
- package/src/wizards/gcp-cost.test.ts +103 -0
- package/src/wizards/gcp-cost.ts +125 -18
- package/src/wizards/gcp.ts +164 -22
- package/stacks/aws/Pulumi.yaml +1 -1
- package/stacks/aws/index.ts +72 -14
- package/stacks/azure/index.ts +108 -21
- package/stacks/gcp/Pulumi.yaml +1 -1
- package/stacks/gcp/README.md +1 -0
- package/stacks/gcp/index.ts +133 -24
- package/stacks/gcp-firebase/Pulumi.yaml +1 -1
- package/stacks/gcp-firebase/index.ts +212 -34
- package/stacks/self-hosted/Pulumi.yaml +3 -0
- package/stacks/self-hosted/README.md +6 -1
- package/stacks/self-hosted/index.ts +40 -5
package/stacks/aws/index.ts
CHANGED
|
@@ -27,7 +27,11 @@
|
|
|
27
27
|
* is to wire those env vars to AWS-native resources.
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
AWS_RDS_CA_BUNDLE,
|
|
32
|
+
cloudFrontRedirectFunctionCode,
|
|
33
|
+
verifyFullQuery,
|
|
34
|
+
} from "@caelo-cms/shared";
|
|
31
35
|
import * as aws from "@pulumi/aws";
|
|
32
36
|
import * as awsx from "@pulumi/awsx";
|
|
33
37
|
import * as pulumi from "@pulumi/pulumi";
|
|
@@ -40,8 +44,10 @@ import {
|
|
|
40
44
|
} from "../../dist/aws-task-roles.js";
|
|
41
45
|
import { generateBootstrapToken } from "../../dist/bootstrap-token.js";
|
|
42
46
|
import {
|
|
47
|
+
DEFAULT_ADMIN_MAX_INSTANCES,
|
|
43
48
|
DEFAULT_GATEWAY_MAX_INSTANCES,
|
|
44
49
|
DEFAULT_MAX_CONNECTIONS,
|
|
50
|
+
DEFAULT_STAGING_GATEWAY_MAX_INSTANCES,
|
|
45
51
|
stackPoolBudget,
|
|
46
52
|
} from "../../dist/pool-budget-stack.js";
|
|
47
53
|
import { ADMIN_MEMORY_DEFAULT, memoryQuantityMiB } from "../../dist/stack-contract.js";
|
|
@@ -82,7 +88,10 @@ const maxConnections = Number.parseInt(
|
|
|
82
88
|
cfg.get("maxConnections") ?? String(DEFAULT_MAX_CONNECTIONS.aws),
|
|
83
89
|
10,
|
|
84
90
|
);
|
|
85
|
-
const adminMaxInstances = Number.parseInt(
|
|
91
|
+
const adminMaxInstances = Number.parseInt(
|
|
92
|
+
cfg.get("adminMaxInstances") ?? String(DEFAULT_ADMIN_MAX_INSTANCES),
|
|
93
|
+
10,
|
|
94
|
+
);
|
|
86
95
|
const gatewayMaxInstances = Number.parseInt(
|
|
87
96
|
cfg.get("gatewayMaxInstances") ?? String(DEFAULT_GATEWAY_MAX_INSTANCES),
|
|
88
97
|
10,
|
|
@@ -91,6 +100,8 @@ const poolBudget = stackPoolBudget("aws", {
|
|
|
91
100
|
maxConnections,
|
|
92
101
|
adminMaxInstances,
|
|
93
102
|
gatewayMaxInstances,
|
|
103
|
+
// #1329 — the staging gateway joins the budget with the staging database.
|
|
104
|
+
stagingGatewayMaxInstances: DEFAULT_STAGING_GATEWAY_MAX_INSTANCES,
|
|
94
105
|
});
|
|
95
106
|
if (_adminMemoryMiB === null) {
|
|
96
107
|
throw new Error(`caelo-aws:adminMemory "${adminMemory}" is not a memory quantity (e.g. 2Gi)`);
|
|
@@ -127,6 +138,9 @@ const postgresPassword = pulumi.secret(randomHex(32));
|
|
|
127
138
|
// #635) never holds admin_role's. bootstrap.sh creates the roles with these
|
|
128
139
|
// (ADMIN_ROLE_PASSWORD / PUBLIC_ROLE_PASSWORD).
|
|
129
140
|
const publicRolePassword = pulumi.secret(randomHex(32));
|
|
141
|
+
// #1329 — the staging gateway's own login on cms_public_staging (created
|
|
142
|
+
// with the database by bootstrap.sh, PUBLIC_STAGING_ROLE_PASSWORD).
|
|
143
|
+
const publicStagingRolePassword = pulumi.secret(randomHex(32));
|
|
130
144
|
const csrfSecret = pulumi.secret(randomHex(32));
|
|
131
145
|
const cookieSecret = pulumi.secret(randomHex(32));
|
|
132
146
|
const anthropicApiKey = pulumi.secret(process.env.ANTHROPIC_API_KEY ?? "");
|
|
@@ -147,6 +161,8 @@ function secret(name: string, value: pulumi.Output<string>): aws.secretsmanager.
|
|
|
147
161
|
|
|
148
162
|
const pgSecret = secret("postgres-password", postgresPassword);
|
|
149
163
|
const publicRoleSecret = secret("public-role-password", publicRolePassword);
|
|
164
|
+
// #1329 — read by nothing yet: the staging gateway's task (#749) will.
|
|
165
|
+
const _publicStagingRoleSecret = secret("public-staging-role-password", publicStagingRolePassword);
|
|
150
166
|
const csrfSecretRes = secret("csrf-secret", csrfSecret);
|
|
151
167
|
const cookieSecretRes = secret("cookie-secret", cookieSecret);
|
|
152
168
|
const anthropicSecretRes = secret("anthropic-api-key", anthropicApiKey);
|
|
@@ -171,9 +187,15 @@ const dbParameters = new aws.rds.ParameterGroup(`${namePrefix}-pg-params`, {
|
|
|
171
187
|
family: "postgres16",
|
|
172
188
|
parameters: [
|
|
173
189
|
{ name: "max_connections", value: String(maxConnections), applyMethod: "pending-reboot" },
|
|
190
|
+
// #1338 — refuse plaintext; every client connects with verify-full.
|
|
191
|
+
{ name: "rds.force_ssl", value: "1", applyMethod: "pending-reboot" },
|
|
174
192
|
],
|
|
175
193
|
});
|
|
176
194
|
|
|
195
|
+
// #1338 — verify-full against Amazon's RDS CA bundle (shipped in every image,
|
|
196
|
+
// shared database-tls.ts); the RDS certificate names the endpoint host.
|
|
197
|
+
const RDS_TLS = verifyFullQuery(AWS_RDS_CA_BUNDLE);
|
|
198
|
+
|
|
177
199
|
const db = new aws.rds.Instance(`${namePrefix}-pg`, {
|
|
178
200
|
engine: "postgres",
|
|
179
201
|
engineVersion: "16.4",
|
|
@@ -196,14 +218,26 @@ const db = new aws.rds.Instance(`${namePrefix}-pg`, {
|
|
|
196
218
|
const adminDatabaseUrl = pulumi
|
|
197
219
|
.all([db.address, db.port, postgresPassword])
|
|
198
220
|
.apply(
|
|
199
|
-
([host, port, pw]) =>
|
|
200
|
-
`postgresql://caelo_admin:${pw}@${host}:${port}/cms_admin?sslmode=require`,
|
|
221
|
+
([host, port, pw]) => `postgresql://caelo_admin:${pw}@${host}:${port}/cms_admin?${RDS_TLS}`,
|
|
201
222
|
);
|
|
202
223
|
const publicDatabaseUrl = pulumi
|
|
203
224
|
.all([db.address, db.port, publicRolePassword])
|
|
225
|
+
.apply(
|
|
226
|
+
([host, port, pw]) => `postgresql://public_role:${pw}@${host}:${port}/cms_public?${RDS_TLS}`,
|
|
227
|
+
);
|
|
228
|
+
// #1329 — the admin's pool on the staging database, and the staging
|
|
229
|
+
// gateway's only login (no task definition reads them before #749).
|
|
230
|
+
const publicStagingAdminDatabaseUrl = pulumi
|
|
231
|
+
.all([db.address, db.port, postgresPassword])
|
|
232
|
+
.apply(
|
|
233
|
+
([host, port, pw]) =>
|
|
234
|
+
`postgresql://caelo_admin:${pw}@${host}:${port}/cms_public_staging?${RDS_TLS}`,
|
|
235
|
+
);
|
|
236
|
+
const publicStagingDatabaseUrl = pulumi
|
|
237
|
+
.all([db.address, db.port, publicStagingRolePassword])
|
|
204
238
|
.apply(
|
|
205
239
|
([host, port, pw]) =>
|
|
206
|
-
`postgresql://
|
|
240
|
+
`postgresql://public_staging_role:${pw}@${host}:${port}/cms_public_staging?${RDS_TLS}`,
|
|
207
241
|
);
|
|
208
242
|
|
|
209
243
|
// === 4. S3 buckets ===
|
|
@@ -441,6 +475,16 @@ new aws.cloudwatch.LogDelivery(
|
|
|
441
475
|
// refuses every server-side render with that gap
|
|
442
476
|
// (capture/capture-backend.ts) instead of running a browser in its own task.
|
|
443
477
|
//
|
|
478
|
+
// FIXME(issue #749): no scheduler tick yet (#1140). On GCP one Cloud
|
|
479
|
+
// Scheduler job calls the admin's /api/internal/scheduler/tick every
|
|
480
|
+
// `schedulerIntervalMinutes` (src/scheduler-setup.ts), and the admin runs
|
|
481
|
+
// its periodic work and plugin workers only on that tick; self-hosted has a
|
|
482
|
+
// scheduler container. The AWS equivalent is one EventBridge Scheduler
|
|
483
|
+
// schedule that runs a small Fargate task (or Lambda) POSTing the same
|
|
484
|
+
// endpoint through the ALB's Cognito gate, with the same 1–15 minute knob.
|
|
485
|
+
// Nothing calls the tick here because no admin task exists on AWS yet; it
|
|
486
|
+
// lands with the admin task in #749.
|
|
487
|
+
//
|
|
444
488
|
// FIXME(issue #696): no in-cloud upgrader or converge job (#819) yet. On
|
|
445
489
|
// GCP Settings → Updates hands app-roll releases to the upgrader job and
|
|
446
490
|
// cloud-setup releases to the converge job; on AWS the admin refuses a
|
|
@@ -450,9 +494,12 @@ const cluster = new aws.ecs.Cluster(`${namePrefix}-ecs`, {
|
|
|
450
494
|
settings: [{ name: "containerInsights", value: "enabled" }],
|
|
451
495
|
});
|
|
452
496
|
|
|
453
|
-
// #
|
|
454
|
-
//
|
|
455
|
-
//
|
|
497
|
+
// #1328 — the MCP-Auth-Proxy (remote MCP's sign-in service) is a service of
|
|
498
|
+
// its own on every provider, with its own task role that may read NO secret.
|
|
499
|
+
// Remote MCP rides Google IAP (gcp stacks only), so on AWS it would run with
|
|
500
|
+
// CAELO_REMOTE_MCP=unavailable and answer a fixed 404. Like the admin and
|
|
501
|
+
// gateway it has no task definition yet: the service lands with #749, in the
|
|
502
|
+
// same shape (own origin, zero minimum tasks, no database env).
|
|
456
503
|
//
|
|
457
504
|
// One task role per service (#635): the gateway's may read only the
|
|
458
505
|
// public_role password, never a secret that unlocks a cms_admin login
|
|
@@ -482,18 +529,23 @@ function taskRole(service: AwsTaskService): aws.iam.Role {
|
|
|
482
529
|
],
|
|
483
530
|
}),
|
|
484
531
|
});
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
.
|
|
490
|
-
|
|
532
|
+
// A service that reads no secret gets no secrets policy at all (an empty
|
|
533
|
+
// policy is malformed, see secretsReadPolicy).
|
|
534
|
+
if (AWS_SERVICE_SECRETS[service].length > 0) {
|
|
535
|
+
new aws.iam.RolePolicy(`${prefix}-task-secrets`, {
|
|
536
|
+
role: role.id,
|
|
537
|
+
policy: pulumi
|
|
538
|
+
.all(AWS_SERVICE_SECRETS[service].map((name) => secretArns[name]))
|
|
539
|
+
.apply(secretsReadPolicy),
|
|
540
|
+
});
|
|
541
|
+
}
|
|
491
542
|
return role;
|
|
492
543
|
}
|
|
493
544
|
|
|
494
545
|
const taskRoles: Record<AwsTaskService, aws.iam.Role> = {
|
|
495
546
|
admin: taskRole("admin"),
|
|
496
547
|
gateway: taskRole("gateway"),
|
|
548
|
+
"mcp-auth-proxy": taskRole("mcp-auth-proxy"),
|
|
497
549
|
};
|
|
498
550
|
|
|
499
551
|
const execRole = new aws.iam.Role(`${namePrefix}-exec-role`, {
|
|
@@ -535,6 +587,7 @@ const dnsRecordsRequired: DnsRecord[] = [
|
|
|
535
587
|
const out: CloudAdapterOutputs = {
|
|
536
588
|
adminDatabaseUrl: adminDatabaseUrl as unknown as string,
|
|
537
589
|
publicDatabaseUrl: publicDatabaseUrl as unknown as string,
|
|
590
|
+
publicStagingDatabaseUrl: publicStagingDatabaseUrl as unknown as string,
|
|
538
591
|
mediaStorageUrl: pulumi.interpolate`s3://${mediaBucket.bucket}` as unknown as string,
|
|
539
592
|
mediaCdnBaseUrl:
|
|
540
593
|
pulumi.interpolate`https://${distribution.domainName}/media` as unknown as string,
|
|
@@ -549,6 +602,9 @@ const out: CloudAdapterOutputs = {
|
|
|
549
602
|
|
|
550
603
|
export const adminDatabaseUrlOut = out.adminDatabaseUrl;
|
|
551
604
|
export const publicDatabaseUrlOut = out.publicDatabaseUrl;
|
|
605
|
+
export const publicStagingDatabaseUrlOut = out.publicStagingDatabaseUrl;
|
|
606
|
+
// #1329 — what the admin task definition (#749) sets as PUBLIC_STAGING_ADMIN_DATABASE_URL.
|
|
607
|
+
export const publicStagingAdminDatabaseUrlOut = publicStagingAdminDatabaseUrl;
|
|
552
608
|
export const mediaStorageUrlOut = out.mediaStorageUrl;
|
|
553
609
|
export const mediaCdnBaseUrlOut = out.mediaCdnBaseUrl;
|
|
554
610
|
export const bootstrapUrlOut = out.bootstrapUrl;
|
|
@@ -563,6 +619,8 @@ export const rdsAddressOut = db.address;
|
|
|
563
619
|
// The task roles the admin-side and gateway task definitions run as.
|
|
564
620
|
export const adminTaskRoleArnOut = taskRoles.admin.arn;
|
|
565
621
|
export const gatewayTaskRoleArnOut = taskRoles.gateway.arn;
|
|
622
|
+
// #1328 — the role the MCP-Auth-Proxy task definition will run as (#749).
|
|
623
|
+
export const mcpAuthProxyTaskRoleArnOut = taskRoles["mcp-auth-proxy"].arn;
|
|
566
624
|
// #1254 — the pool env the admin and gateway task definitions set.
|
|
567
625
|
export const poolBudgetEnvOut = poolBudget.env;
|
|
568
626
|
|
package/stacks/azure/index.ts
CHANGED
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
* 4. Azure Front Door Standard serving the static website on the primary
|
|
14
14
|
* domain with a managed certificate — files served as files, no compute
|
|
15
15
|
* on the request path (CLAUDE.md §11.B Tier 1).
|
|
16
|
-
* 5. Azure Container Apps (admin/gateway/orchestrator/runner
|
|
16
|
+
* 5. Azure Container Apps (admin/gateway/orchestrator/runner, and the
|
|
17
|
+
* MCP-Auth-Proxy without any secret, #1328),
|
|
17
18
|
* mounted with Key Vault secrets via managed identity.
|
|
18
19
|
* 6. Key Vault entries (postgres-password, csrf-secret, cookie-secret,
|
|
19
20
|
* anthropic-api-key, resend-api-key).
|
|
@@ -34,16 +35,25 @@
|
|
|
34
35
|
* env vars wired by this stack.
|
|
35
36
|
*/
|
|
36
37
|
|
|
38
|
+
import { verifyFullQuery } from "@caelo-cms/shared";
|
|
37
39
|
import * as azure from "@pulumi/azure-native";
|
|
38
40
|
import * as pulumi from "@pulumi/pulumi";
|
|
39
41
|
import type { CloudAdapterOutputs, DnsRecord } from "../../dist/adapter.js";
|
|
40
42
|
import { azureFrontDoorDnsRecords } from "../../dist/azure-front-door.js";
|
|
41
43
|
import { generateBootstrapToken } from "../../dist/bootstrap-token.js";
|
|
42
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
DEFAULT_MAX_CONNECTIONS,
|
|
46
|
+
DEFAULT_STAGING_GATEWAY_MAX_INSTANCES,
|
|
47
|
+
stackPoolBudget,
|
|
48
|
+
} from "../../dist/pool-budget-stack.js";
|
|
43
49
|
import {
|
|
44
50
|
ADMIN_MEMORY_DEFAULT,
|
|
45
51
|
azureContainerAppResources,
|
|
52
|
+
GATEWAY_ENVIRONMENT_ENV,
|
|
46
53
|
GATEWAY_TRUSTED_PROXY_HOPS,
|
|
54
|
+
MCP_AUTH_PROXY_TRUSTED_PROXY_HOPS,
|
|
55
|
+
REMOTE_MCP_MODE,
|
|
56
|
+
REMOTE_MCP_MODE_ENV,
|
|
47
57
|
TRUSTED_PROXY_HOPS_ENV,
|
|
48
58
|
} from "../../dist/stack-contract.js";
|
|
49
59
|
import {
|
|
@@ -83,6 +93,8 @@ const poolBudget = stackPoolBudget("azure", {
|
|
|
83
93
|
maxConnections,
|
|
84
94
|
adminMaxInstances: ADMIN_SIDE_APPS * MAX_REPLICAS,
|
|
85
95
|
gatewayMaxInstances: MAX_REPLICAS,
|
|
96
|
+
// #1329 — the staging gateway joins the budget with the staging database.
|
|
97
|
+
stagingGatewayMaxInstances: DEFAULT_STAGING_GATEWAY_MAX_INSTANCES,
|
|
86
98
|
});
|
|
87
99
|
// #553 — the admin runs the Lighthouse quality audit; same knob + default
|
|
88
100
|
// as every adapter (stack-contract.ts). Container Apps only accepts fixed
|
|
@@ -111,6 +123,9 @@ const postgresPassword = pulumi.secret(randomHex(32));
|
|
|
111
123
|
// #635) never holds admin_role's. bootstrap.sh creates the roles with these
|
|
112
124
|
// (ADMIN_ROLE_PASSWORD / PUBLIC_ROLE_PASSWORD).
|
|
113
125
|
const publicRolePassword = pulumi.secret(randomHex(32));
|
|
126
|
+
// #1329 — the staging gateway's own login on cms_public_staging (created
|
|
127
|
+
// with the database by bootstrap.sh, PUBLIC_STAGING_ROLE_PASSWORD).
|
|
128
|
+
const publicStagingRolePassword = pulumi.secret(randomHex(32));
|
|
114
129
|
const csrfSecret = pulumi.secret(randomHex(32));
|
|
115
130
|
const cookieSecret = pulumi.secret(randomHex(32));
|
|
116
131
|
const anthropicApiKey = pulumi.secret(process.env.ANTHROPIC_API_KEY ?? "");
|
|
@@ -140,6 +155,8 @@ function keyVaultSecret(shortName: string, value: pulumi.Output<string>): azure.
|
|
|
140
155
|
|
|
141
156
|
const _pgSecret = keyVaultSecret("pg-password", postgresPassword);
|
|
142
157
|
keyVaultSecret("public-role-password", publicRolePassword);
|
|
158
|
+
// #1329 — read by nothing yet: the staging gateway's app (#750) will.
|
|
159
|
+
keyVaultSecret("public-staging-role-password", publicStagingRolePassword);
|
|
143
160
|
keyVaultSecret("csrf-secret", csrfSecret);
|
|
144
161
|
keyVaultSecret("cookie-secret", cookieSecret);
|
|
145
162
|
keyVaultSecret("anthropic-api-key", anthropicApiKey);
|
|
@@ -190,19 +207,44 @@ const _pgPublic = new azure.dbforpostgresql.Database(`${namePrefix}-cms-public-d
|
|
|
190
207
|
databaseName: "cms_public",
|
|
191
208
|
charset: "UTF8",
|
|
192
209
|
});
|
|
210
|
+
// #1329 — staging's own data, the twin of cms_public on the same server.
|
|
211
|
+
const _pgPublicStaging = new azure.dbforpostgresql.Database(`${namePrefix}-cms-public-staging-db`, {
|
|
212
|
+
resourceGroupName: rg.name,
|
|
213
|
+
serverName: pgServer.name,
|
|
214
|
+
databaseName: "cms_public_staging",
|
|
215
|
+
charset: "UTF8",
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// #1338 — verify-full to the server's FQDN. Flexible Server's certificate chains
|
|
219
|
+
// to public roots (DigiCert Global Root G2, Microsoft RSA Root CA 2017) that
|
|
220
|
+
// Bun trusts out of the box, so no sslrootcert (shared database-tls.ts).
|
|
221
|
+
const AZURE_TLS = verifyFullQuery();
|
|
193
222
|
|
|
194
223
|
const adminDatabaseUrl = pulumi
|
|
195
224
|
.all([pgServer.fullyQualifiedDomainName, postgresPassword])
|
|
196
|
-
.apply(([host, pw]) => `postgresql://caelo_admin:${pw}@${host}:5432/cms_admin
|
|
225
|
+
.apply(([host, pw]) => `postgresql://caelo_admin:${pw}@${host}:5432/cms_admin?${AZURE_TLS}`);
|
|
197
226
|
// What the admin connects to cms_public with (DDL, migrations, moderation).
|
|
198
227
|
const publicAdminDatabaseUrl = pulumi
|
|
199
228
|
.all([pgServer.fullyQualifiedDomainName, postgresPassword])
|
|
200
|
-
.apply(([host, pw]) => `postgresql://caelo_admin:${pw}@${host}:5432/cms_public
|
|
229
|
+
.apply(([host, pw]) => `postgresql://caelo_admin:${pw}@${host}:5432/cms_public?${AZURE_TLS}`);
|
|
201
230
|
// The gateway's only login (#613, #635): public_role on cms_public. It has
|
|
202
231
|
// no cms_admin login at all (CLAUDE.md §2).
|
|
203
232
|
const publicDatabaseUrl = pulumi
|
|
204
233
|
.all([pgServer.fullyQualifiedDomainName, publicRolePassword])
|
|
205
|
-
.apply(([host, pw]) => `postgresql://public_role:${pw}@${host}:5432/cms_public
|
|
234
|
+
.apply(([host, pw]) => `postgresql://public_role:${pw}@${host}:5432/cms_public?${AZURE_TLS}`);
|
|
235
|
+
// #1329 — the admin's pool on the staging database (plugin schemas, the
|
|
236
|
+
// staging half of the projection), and the staging gateway's only login.
|
|
237
|
+
const publicStagingAdminDatabaseUrl = pulumi
|
|
238
|
+
.all([pgServer.fullyQualifiedDomainName, postgresPassword])
|
|
239
|
+
.apply(
|
|
240
|
+
([host, pw]) => `postgresql://caelo_admin:${pw}@${host}:5432/cms_public_staging?${AZURE_TLS}`,
|
|
241
|
+
);
|
|
242
|
+
const publicStagingDatabaseUrl = pulumi
|
|
243
|
+
.all([pgServer.fullyQualifiedDomainName, publicStagingRolePassword])
|
|
244
|
+
.apply(
|
|
245
|
+
([host, pw]) =>
|
|
246
|
+
`postgresql://public_staging_role:${pw}@${host}:5432/cms_public_staging?${AZURE_TLS}`,
|
|
247
|
+
);
|
|
206
248
|
|
|
207
249
|
// === 4. Storage account + containers ===
|
|
208
250
|
const storage = new azure.storage.StorageAccount(`${namePrefix}-st`, {
|
|
@@ -399,6 +441,15 @@ const logWorkspace = new azure.operationalinsights.Workspace(`${namePrefix}-logs
|
|
|
399
441
|
// refuses every server-side render with that gap
|
|
400
442
|
// (capture/capture-backend.ts) instead of running a browser in its own app.
|
|
401
443
|
//
|
|
444
|
+
// FIXME(issue #750): no scheduler tick yet (#1140). On GCP one Cloud
|
|
445
|
+
// Scheduler job calls the admin's /api/internal/scheduler/tick every
|
|
446
|
+
// `schedulerIntervalMinutes` (src/scheduler-setup.ts), and the admin runs
|
|
447
|
+
// its periodic work and plugin workers only on that tick; self-hosted has a
|
|
448
|
+
// scheduler container. The Azure equivalent is a scheduled Container Apps
|
|
449
|
+
// job (or Logic App recurrence) POSTing the same endpoint behind Easy Auth,
|
|
450
|
+
// with the same 1–15 minute knob. Nothing calls the tick here because no
|
|
451
|
+
// admin app exists on Azure yet; it lands with the admin in #750.
|
|
452
|
+
//
|
|
402
453
|
// FIXME(issue #696): no in-cloud upgrader or converge job (#819) yet. On
|
|
403
454
|
// GCP Settings → Updates hands app-roll releases to the upgrader job and
|
|
404
455
|
// cloud-setup releases to the converge job; on Azure the admin refuses a
|
|
@@ -437,6 +488,12 @@ interface ContainerAppArgs {
|
|
|
437
488
|
readonly extraEnv?: ReadonlyArray<{ name: string; value: pulumi.Input<string> }>;
|
|
438
489
|
/** Defaults to 0.5 vCPU / 1 GiB. */
|
|
439
490
|
readonly resources?: { readonly cpu: number; readonly memory: string };
|
|
491
|
+
/**
|
|
492
|
+
* #1328 — a service that reads nothing of the install: no CAELO_ENV, no
|
|
493
|
+
* media URL, only `CAELO_PROVIDER` plus {@link extraEnv}, and zero
|
|
494
|
+
* minimum replicas in every environment (E14 a of #763).
|
|
495
|
+
*/
|
|
496
|
+
readonly isolated?: true;
|
|
440
497
|
}
|
|
441
498
|
|
|
442
499
|
function containerApp(args: ContainerAppArgs): azure.app.ContainerApp {
|
|
@@ -454,7 +511,10 @@ function containerApp(args: ContainerAppArgs): azure.app.ContainerApp {
|
|
|
454
511
|
},
|
|
455
512
|
},
|
|
456
513
|
template: {
|
|
457
|
-
scale: {
|
|
514
|
+
scale: {
|
|
515
|
+
minReplicas: args.isolated || env !== "production" ? 0 : 1,
|
|
516
|
+
maxReplicas: MAX_REPLICAS,
|
|
517
|
+
},
|
|
458
518
|
containers: [
|
|
459
519
|
{
|
|
460
520
|
name: args.serviceName,
|
|
@@ -462,16 +522,18 @@ function containerApp(args: ContainerAppArgs): azure.app.ContainerApp {
|
|
|
462
522
|
image:
|
|
463
523
|
cfg.get(`image-${args.serviceName}`) ??
|
|
464
524
|
`${namePrefix}.azurecr.io/${args.serviceName}:latest`,
|
|
465
|
-
env:
|
|
466
|
-
{ name: "CAELO_PROVIDER", value: "azure" },
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
525
|
+
env: args.isolated
|
|
526
|
+
? [{ name: "CAELO_PROVIDER", value: "azure" }, ...(args.extraEnv ?? [])]
|
|
527
|
+
: [
|
|
528
|
+
{ name: "CAELO_PROVIDER", value: "azure" },
|
|
529
|
+
{ name: "CAELO_ENV", value: env },
|
|
530
|
+
...args.databaseEnv,
|
|
531
|
+
{
|
|
532
|
+
name: "MEDIA_STORAGE_URL",
|
|
533
|
+
value: pulumi.interpolate`https://${storage.name}.blob.core.windows.net/media`,
|
|
534
|
+
},
|
|
535
|
+
...(args.extraEnv ?? []),
|
|
536
|
+
],
|
|
475
537
|
resources: args.resources ?? { cpu: 0.5, memory: "1.0Gi" },
|
|
476
538
|
},
|
|
477
539
|
],
|
|
@@ -482,6 +544,7 @@ function containerApp(args: ContainerAppArgs): azure.app.ContainerApp {
|
|
|
482
544
|
const adminDatabaseEnv = [
|
|
483
545
|
{ name: "ADMIN_DATABASE_URL", value: adminDatabaseUrl },
|
|
484
546
|
{ name: "PUBLIC_ADMIN_DATABASE_URL", value: publicAdminDatabaseUrl },
|
|
547
|
+
{ name: "PUBLIC_STAGING_ADMIN_DATABASE_URL", value: publicStagingAdminDatabaseUrl },
|
|
485
548
|
...poolBudget.env.admin,
|
|
486
549
|
];
|
|
487
550
|
const adminApp = containerApp({
|
|
@@ -498,11 +561,33 @@ const _gatewayApp = containerApp({
|
|
|
498
561
|
{ name: "PUBLIC_DATABASE_URL", value: publicDatabaseUrl },
|
|
499
562
|
...poolBudget.env.gateway,
|
|
500
563
|
],
|
|
501
|
-
// Which X-Forwarded-For entry is the visitor (api-gateway client-ip.ts)
|
|
502
|
-
// #
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
564
|
+
// Which X-Forwarded-For entry is the visitor (api-gateway client-ip.ts),
|
|
565
|
+
// and (#1329) that this is the live site's gateway.
|
|
566
|
+
extraEnv: [
|
|
567
|
+
{ name: TRUSTED_PROXY_HOPS_ENV, value: String(GATEWAY_TRUSTED_PROXY_HOPS.azure) },
|
|
568
|
+
{ name: GATEWAY_ENVIRONMENT_ENV, value: "live" },
|
|
569
|
+
],
|
|
570
|
+
});
|
|
571
|
+
// #1328 — the MCP-Auth-Proxy, its own Container App and so its own FQDN:
|
|
572
|
+
// remote MCP's sign-in pages never share an origin with the site's module
|
|
573
|
+
// JS. Remote MCP needs the admin behind Google IAP, which Azure does not
|
|
574
|
+
// have, so it runs with CAELO_REMOTE_MCP=unavailable and answers everything
|
|
575
|
+
// but its health check (`/api/mcp/health`) with one fixed 404; the admin
|
|
576
|
+
// reports remote MCP as not available here. No database URL, no secret
|
|
577
|
+
// and no managed identity, because there is nothing it may read. Same
|
|
578
|
+
// shape as on every provider (E11 of #763), at zero replicas until a
|
|
579
|
+
// request comes.
|
|
580
|
+
const _mcpAuthProxyApp = containerApp({
|
|
581
|
+
serviceName: "mcp-auth-proxy",
|
|
582
|
+
databaseEnv: [],
|
|
583
|
+
isolated: true,
|
|
584
|
+
resources: { cpu: 0.25, memory: "0.5Gi" },
|
|
585
|
+
extraEnv: [
|
|
586
|
+
{ name: REMOTE_MCP_MODE_ENV, value: REMOTE_MCP_MODE.azure },
|
|
587
|
+
{ name: TRUSTED_PROXY_HOPS_ENV, value: String(MCP_AUTH_PROXY_TRUSTED_PROXY_HOPS.azure) },
|
|
588
|
+
// The app's ingress targets 8080 (containerApp above).
|
|
589
|
+
{ name: "PORT", value: "8080" },
|
|
590
|
+
],
|
|
506
591
|
});
|
|
507
592
|
const _orchestratorApp = containerApp({
|
|
508
593
|
serviceName: "orchestrator",
|
|
@@ -526,6 +611,7 @@ const dnsRecordsRequired = pulumi
|
|
|
526
611
|
const out: CloudAdapterOutputs = {
|
|
527
612
|
adminDatabaseUrl: adminDatabaseUrl as unknown as string,
|
|
528
613
|
publicDatabaseUrl: publicDatabaseUrl as unknown as string,
|
|
614
|
+
publicStagingDatabaseUrl: publicStagingDatabaseUrl as unknown as string,
|
|
529
615
|
mediaStorageUrl:
|
|
530
616
|
pulumi.interpolate`https://${storage.name}.blob.core.windows.net/media` as unknown as string,
|
|
531
617
|
mediaCdnBaseUrl: pulumi.interpolate`https://${domain}/media` as unknown as string,
|
|
@@ -539,6 +625,7 @@ const out: CloudAdapterOutputs = {
|
|
|
539
625
|
|
|
540
626
|
export const adminDatabaseUrlOut = out.adminDatabaseUrl;
|
|
541
627
|
export const publicDatabaseUrlOut = out.publicDatabaseUrl;
|
|
628
|
+
export const publicStagingDatabaseUrlOut = out.publicStagingDatabaseUrl;
|
|
542
629
|
export const mediaStorageUrlOut = out.mediaStorageUrl;
|
|
543
630
|
export const mediaCdnBaseUrlOut = out.mediaCdnBaseUrl;
|
|
544
631
|
export const bootstrapUrlOut = out.bootstrapUrl;
|
package/stacks/gcp/Pulumi.yaml
CHANGED
|
@@ -55,7 +55,7 @@ config:
|
|
|
55
55
|
description: Admin Cloud Run memory. 2Gi leaves room for the Lighthouse quality audit next to editor requests; billed only while an instance runs.
|
|
56
56
|
caelo-gcp:adminMaxInstances:
|
|
57
57
|
type: string
|
|
58
|
-
default: "
|
|
58
|
+
default: "4"
|
|
59
59
|
description: |
|
|
60
60
|
Admin Cloud Run max instances. Each instance gets an equal share of
|
|
61
61
|
the connection budget (docs/dev/connection-budget.md): at the
|
package/stacks/gcp/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Pulumi stack provisioning Caelo on GCP managed services. Implements the shared `
|
|
|
12
12
|
| Container runtime | Four Cloud Run services (admin / gateway / orchestrator / runner) |
|
|
13
13
|
| Secret store | Secret Manager: postgres-password (admin_role) + secret-kek (Pulumi); internal-secret, tool-approval-secret and public-role-password (created by the CLI before `pulumi up`, see `src/runtime-secrets.ts`). Cloud Run reads each as a `secretKeyRef`; database URLs carry no password. The gateway's service account reads only `public-role-password` (#613, #635: the gateway has no cms_admin login). |
|
|
14
14
|
| Edge-log sink | Cloud Logging project sink → BigQuery dataset `<env>_edge_logs` (queryable by P12A analytics plugin) |
|
|
15
|
+
| Scheduler tick (CLI-owned, #1140) | One Cloud Scheduler job `caelo-<env>-scheduler-tick` starts the Workflows workflow of the same name every `schedulerIntervalMinutes` (1–15, default 5; `--scheduler-interval-minutes` on the installer, recorded in install.json). The workflow signs an IAP credential as `caelo-<env>-scheduler` and POSTs the admin's `/api/internal/scheduler/tick`, which runs the due periodic work and plugin workers. Set up by the installer and `upgrade` (`src/scheduler-setup.ts`), not by this stack. |
|
|
15
16
|
|
|
16
17
|
The Caelo runtime never knows it's on GCP — every Cloud Run service consumes plain `DATABASE_URL` / `MEDIA_STORAGE_URL` / `SECRETS_PROVIDER` env vars.
|
|
17
18
|
|