@caelo-cms/provisioning 0.11.8 → 0.11.10
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/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 +6 -1
- package/dist/adopt-existing.d.ts.map +1 -1
- package/dist/adopt-existing.js +86 -0
- package/dist/adopt-existing.js.map +1 -1
- package/dist/agent/command.d.ts +20 -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 +65 -3
- 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.js +12 -3
- package/dist/cli.js.map +1 -1
- package/dist/cloudsql-tls.d.ts +63 -0
- package/dist/cloudsql-tls.d.ts.map +1 -0
- package/dist/cloudsql-tls.js +289 -0
- package/dist/cloudsql-tls.js.map +1 -0
- package/dist/compose.d.ts +29 -6
- package/dist/compose.d.ts.map +1 -1
- package/dist/compose.js +95 -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-job-gcp.d.ts.map +1 -1
- package/dist/converge-job-gcp.js +2 -11
- package/dist/converge-job-gcp.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 +21 -0
- package/dist/gcp-names.d.ts.map +1 -1
- package/dist/gcp-names.js +24 -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 +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -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 +24 -1
- package/dist/infra-contract.js.map +1 -1
- package/dist/install-state.d.ts +6 -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 +17 -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/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 +9 -0
- package/dist/runtime-secrets.d.ts.map +1 -1
- package/dist/runtime-secrets.js +21 -10
- package/dist/runtime-secrets.js.map +1 -1
- 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 +34 -0
- package/dist/self-hosted-roles.d.ts.map +1 -1
- package/dist/self-hosted-roles.js +52 -0
- package/dist/self-hosted-roles.js.map +1 -1
- 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 +15 -6
- package/dist/self-hosted-upgrade.d.ts.map +1 -1
- package/dist/self-hosted-upgrade.js +72 -23
- package/dist/self-hosted-upgrade.js.map +1 -1
- package/dist/stack-contract.d.ts +170 -25
- package/dist/stack-contract.d.ts.map +1 -1
- package/dist/stack-contract.js +314 -37
- 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/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.map +1 -1
- package/dist/upgrade/converge.js +99 -12
- 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 +13 -3
- package/dist/upgrade/upgrade.d.ts.map +1 -1
- package/dist/upgrade/upgrade.js +34 -2
- package/dist/upgrade/upgrade.js.map +1 -1
- package/dist/upgrader-gcp.d.ts +12 -0
- package/dist/upgrader-gcp.d.ts.map +1 -1
- package/dist/upgrader-gcp.js +49 -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/wizards/gcp-cost.d.ts.map +1 -1
- package/dist/wizards/gcp-cost.js +22 -7
- package/dist/wizards/gcp-cost.js.map +1 -1
- package/dist/wizards/gcp.d.ts.map +1 -1
- package/dist/wizards/gcp.js +43 -17
- package/dist/wizards/gcp.js.map +1 -1
- package/package.json +2 -2
- package/src/admin-domain.test.ts +9 -8
- package/src/admin-domain.ts +13 -3
- package/src/admin-memory.test.ts +1 -0
- package/src/adopt-existing.test.ts +39 -0
- package/src/adopt-existing.ts +83 -1
- package/src/agent/command.test.ts +49 -1
- package/src/agent/command.ts +36 -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 +3 -0
- 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.ts +12 -1
- package/src/cloudsql-tls.test.ts +225 -0
- package/src/cloudsql-tls.ts +352 -0
- package/src/compose.ts +125 -24
- package/src/converge-checkpoint.ts +8 -1
- package/src/converge-job-gcp.ts +2 -11
- package/src/database-tls-builders.test.ts +55 -0
- package/src/deployed-release.test.ts +104 -40
- package/src/deployed-release.ts +30 -9
- package/src/gateway-env-isolation.test.ts +10 -5
- package/src/gcp-names.ts +31 -0
- package/src/gcp-url-map.test.ts +6 -8
- package/src/gcp-url-map.ts +6 -2
- package/src/index.test.ts +7 -1
- package/src/index.ts +1 -0
- package/src/infra-contract.test.ts +5 -3
- package/src/infra-contract.ts +24 -1
- package/src/install-state.ts +26 -4
- package/src/lifecycle.ts +20 -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/operator-access-stacks.test.ts +1 -1
- package/src/operator-access.test.ts +5 -4
- package/src/pool-budget-stacks.test.ts +1 -1
- 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 +20 -7
- package/src/runtime-secrets.ts +50 -9
- package/src/seal-key-rotation.test.ts +2 -2
- package/src/seal-key-rotation.ts +25 -25
- package/src/self-hosted-compose.test.ts +108 -5
- 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.test.ts +54 -0
- package/src/self-hosted-roles.ts +58 -0
- package/src/self-hosted-start.test.ts +34 -2
- package/src/self-hosted-start.ts +20 -2
- package/src/self-hosted-upgrade.test.ts +103 -14
- package/src/self-hosted-upgrade.ts +115 -29
- package/src/stack-contract-parity.test.ts +79 -12
- package/src/stack-contract.test.ts +169 -29
- package/src/stack-contract.ts +362 -42
- package/src/stack-converge-secrets.test.ts +26 -13
- package/src/stack-converge.test.ts +199 -26
- package/src/stack-converge.ts +92 -30
- package/src/state-store.test.ts +2 -1
- package/src/upgrade/app-roll.ts +97 -19
- package/src/upgrade/converge.ts +120 -11
- 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 +353 -44
- package/src/upgrade/upgrade.ts +55 -6
- package/src/upgrader-gcp.ts +65 -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/wizards/gcp-cost.test.ts +50 -0
- package/src/wizards/gcp-cost.ts +24 -7
- package/src/wizards/gcp.ts +55 -14
- package/stacks/aws/index.ts +32 -14
- package/stacks/azure/index.ts +57 -18
- package/stacks/gcp/index.ts +83 -23
- package/stacks/gcp-firebase/index.ts +162 -33
- package/stacks/self-hosted/README.md +2 -1
- package/stacks/self-hosted/index.ts +11 -1
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
* - Static site: Firebase Hosting site (no LB, no BackendBucket)
|
|
8
8
|
* - Admin: Cloud Run + custom domain mapping (admin.<domain>)
|
|
9
9
|
* + IAP-on-Cloud-Run (no LB IAP)
|
|
10
|
-
* - Gateway: Cloud Run
|
|
11
|
-
* no Cloud Armor)
|
|
10
|
+
* - Gateway: Cloud Run `caelo-<env>-data-gateway` + Firebase
|
|
11
|
+
* Hosting `rewrites` (no LB, no Cloud Armor)
|
|
12
|
+
* - MCP-Auth-Proxy: Cloud Run on its own run.app URL (#1328; the
|
|
13
|
+
* service that was the gateway, E13 a of #763)
|
|
12
14
|
* - Database: Cloud SQL Postgres on private VPC IP only (same
|
|
13
15
|
* as `gcp/`)
|
|
14
16
|
* - Workers: share admin Cloud Run (same as `gcp/`)
|
|
@@ -35,6 +37,7 @@ import {
|
|
|
35
37
|
gcpBucketName,
|
|
36
38
|
gcpSecretId,
|
|
37
39
|
MCP_IAP_SERVICE_ACCOUNT_ID,
|
|
40
|
+
mcpAuthProxyServiceAccountId,
|
|
38
41
|
runServiceAccountId,
|
|
39
42
|
} from "../../dist/gcp-names.js";
|
|
40
43
|
import {
|
|
@@ -48,17 +51,27 @@ import {
|
|
|
48
51
|
adminMediaVolume,
|
|
49
52
|
adminMediaVolumeTemplate,
|
|
50
53
|
CLOUD_RUN_IGNORE_CHANGES,
|
|
54
|
+
CLOUD_SQL_PSA_CONNECTION_TYPE,
|
|
55
|
+
CLOUD_SQL_SERVER_CA_MODE,
|
|
56
|
+
CLOUD_SQL_SSL_MODE,
|
|
51
57
|
type CloudRunEnvVar,
|
|
52
58
|
type CloudRunSlug,
|
|
59
|
+
cloudSqlDnsZoneName,
|
|
60
|
+
cloudSqlPrivateDnsName,
|
|
61
|
+
DEFAULT_MCP_AUTH_PROXY_MAX_INSTANCES,
|
|
53
62
|
databaseUrls,
|
|
54
63
|
defaultStagingHost,
|
|
55
|
-
|
|
64
|
+
fixedCloudRunServiceName,
|
|
56
65
|
gatewayEnvContract,
|
|
66
|
+
INTERIM_FORWARD_ORIGIN_ENV,
|
|
67
|
+
MCP_AUTH_PROXY_TIMEOUT_SECONDS,
|
|
68
|
+
mcpAuthProxyEnvContract,
|
|
57
69
|
REMOTE_MCP_IDENTITY_CONFIG,
|
|
58
70
|
type RuntimeSecret,
|
|
59
71
|
remoteMcpIdentityStackEnv,
|
|
60
72
|
runtimeSecretBindings,
|
|
61
73
|
SERVICE_CPU_IDLE,
|
|
74
|
+
SERVICE_VPC_EGRESS,
|
|
62
75
|
secretFileVolumesTemplate,
|
|
63
76
|
} from "../../dist/stack-contract.js";
|
|
64
77
|
|
|
@@ -293,6 +306,11 @@ const sqlInstance = new gcp.sql.DatabaseInstance(
|
|
|
293
306
|
ipv4Enabled: false,
|
|
294
307
|
privateNetwork: network.id,
|
|
295
308
|
enablePrivatePathForGoogleCloudServices: true,
|
|
309
|
+
// #1338 — the shared CA names the instance's DNS name in its server
|
|
310
|
+
// certificate, so every client verifies it (sslmode=verify-full);
|
|
311
|
+
// unencrypted connections are refused outright.
|
|
312
|
+
serverCaMode: CLOUD_SQL_SERVER_CA_MODE,
|
|
313
|
+
sslMode: CLOUD_SQL_SSL_MODE,
|
|
296
314
|
},
|
|
297
315
|
databaseFlags: [
|
|
298
316
|
{ name: "max_connections", value: maxConnections.toString() },
|
|
@@ -335,9 +353,49 @@ new gcp.sql.User(
|
|
|
335
353
|
opts,
|
|
336
354
|
);
|
|
337
355
|
|
|
356
|
+
// #1338 — the instance's DNS name, resolved to its private IP by a private
|
|
357
|
+
// zone in the VPC (Cloud SQL assigns the name, it does not resolve it).
|
|
358
|
+
// Every client dials this name with sslmode=verify-full; the certificate
|
|
359
|
+
// names no IP. `cms-provision upgrade` converges the same zone and record
|
|
360
|
+
// through gcloud (cloudsql-tls.ts); the installer adopts them (#1079).
|
|
361
|
+
const sqlDnsName = sqlInstance.dnsNames.apply((names) => {
|
|
362
|
+
const name = cloudSqlPrivateDnsName(names);
|
|
363
|
+
if (!name) {
|
|
364
|
+
throw new Error(
|
|
365
|
+
`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)`,
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
return name;
|
|
369
|
+
});
|
|
370
|
+
const sqlDnsZone = new gcp.dns.ManagedZone(
|
|
371
|
+
`${namePrefix}-pg-dns`,
|
|
372
|
+
{
|
|
373
|
+
name: cloudSqlDnsZoneName(env),
|
|
374
|
+
dnsName: pulumi.interpolate`${sqlDnsName}.`,
|
|
375
|
+
visibility: "private",
|
|
376
|
+
privateVisibilityConfig: { networks: [{ networkUrl: network.id }] },
|
|
377
|
+
description: `Caelo ${env}: the Cloud SQL instance's DNS name inside the VPC (#1338)`,
|
|
378
|
+
},
|
|
379
|
+
opts,
|
|
380
|
+
);
|
|
381
|
+
const sqlDnsRecord = new gcp.dns.RecordSet(
|
|
382
|
+
`${namePrefix}-pg-dns-a`,
|
|
383
|
+
{
|
|
384
|
+
// Literal names, not the zone's outputs: the installer can then adopt
|
|
385
|
+
// a record an upgrade created (adopt-existing.ts) from the preview.
|
|
386
|
+
managedZone: cloudSqlDnsZoneName(env),
|
|
387
|
+
name: pulumi.interpolate`${sqlDnsName}.`,
|
|
388
|
+
type: "A",
|
|
389
|
+
ttl: 300,
|
|
390
|
+
rrdatas: [sqlInstance.privateIpAddress],
|
|
391
|
+
},
|
|
392
|
+
{ ...opts, dependsOn: [sqlDnsZone] },
|
|
393
|
+
);
|
|
394
|
+
|
|
338
395
|
// Password-less connection URLs (stack-contract.ts databaseUrls); the
|
|
339
|
-
// services get the password as a Secret Manager reference.
|
|
340
|
-
|
|
396
|
+
// services get the password as a Secret Manager reference. Tied to the
|
|
397
|
+
// record so no revision boots before its database host resolves.
|
|
398
|
+
const dbUrls = pulumi.all([sqlDnsName, sqlDnsRecord.id]).apply(([host]) => databaseUrls(host));
|
|
341
399
|
|
|
342
400
|
// =========================================================================
|
|
343
401
|
// Media bucket — private, signed-URL access only (same as `gcp` stack)
|
|
@@ -380,9 +438,22 @@ const gatewaySa = new gcp.serviceaccount.Account(
|
|
|
380
438
|
},
|
|
381
439
|
opts,
|
|
382
440
|
);
|
|
441
|
+
// #1328 — the MCP-Auth-Proxy's own SA: secretAccessor on its two secrets
|
|
442
|
+
// below and nothing else — no project role, not even the log writer (Cloud
|
|
443
|
+
// Run ships a container's stdout to Cloud Logging without one).
|
|
444
|
+
const mcpAuthProxySa = new gcp.serviceaccount.Account(
|
|
445
|
+
`${namePrefix}-mcp-auth-proxy-sa`,
|
|
446
|
+
{
|
|
447
|
+
accountId: mcpAuthProxyServiceAccountId(env),
|
|
448
|
+
displayName: `Caelo ${env} MCP-Auth-Proxy`,
|
|
449
|
+
createIgnoreAlreadyExists: true,
|
|
450
|
+
},
|
|
451
|
+
opts,
|
|
452
|
+
);
|
|
383
453
|
const serviceSa: Record<CloudRunSlug, gcp.serviceaccount.Account> = {
|
|
384
454
|
admin: runSa,
|
|
385
455
|
gateway: gatewaySa,
|
|
456
|
+
"mcp-auth-proxy": mcpAuthProxySa,
|
|
386
457
|
};
|
|
387
458
|
|
|
388
459
|
// secretAccessor for each service's SA on exactly the secrets its env reads.
|
|
@@ -391,6 +462,7 @@ const serviceSa: Record<CloudRunSlug, gcp.serviceaccount.Account> = {
|
|
|
391
462
|
const secretBindings: Record<CloudRunSlug, gcp.secretmanager.SecretIamMember[]> = {
|
|
392
463
|
admin: [],
|
|
393
464
|
gateway: [],
|
|
465
|
+
"mcp-auth-proxy": [],
|
|
394
466
|
};
|
|
395
467
|
for (const binding of runtimeSecretBindings()) {
|
|
396
468
|
secretBindings[binding.service].push(
|
|
@@ -533,11 +605,19 @@ const firebaseCustomDomain = new gcp.firebase.HostingCustomDomain(
|
|
|
533
605
|
);
|
|
534
606
|
|
|
535
607
|
// =========================================================================
|
|
536
|
-
// Cloud Run services — admin
|
|
608
|
+
// Cloud Run services — admin, data gateway, MCP-Auth-Proxy
|
|
537
609
|
// =========================================================================
|
|
538
610
|
|
|
539
611
|
interface CloudRunArgs {
|
|
540
|
-
readonly serviceName:
|
|
612
|
+
readonly serviceName: CloudRunSlug;
|
|
613
|
+
/**
|
|
614
|
+
* The Pulumi resource name, when it is not `${namePrefix}-<serviceName>`.
|
|
615
|
+
* #1328 E13 a: the proxy keeps the logical name the gateway had, so Pulumi
|
|
616
|
+
* keeps the same resource and its auto-generated service name — an alias
|
|
617
|
+
* under a new name would let the provider pick a new name, and a new
|
|
618
|
+
* service means a new run.app URL.
|
|
619
|
+
*/
|
|
620
|
+
readonly resourceName?: string;
|
|
541
621
|
readonly minInstances: number;
|
|
542
622
|
readonly maxInstances: number;
|
|
543
623
|
readonly memory: string;
|
|
@@ -582,9 +662,13 @@ function imageRef(service: string): string {
|
|
|
582
662
|
const remoteMcpEnv = remoteMcpIdentityStackEnv(cfg.get(REMOTE_MCP_IDENTITY_CONFIG));
|
|
583
663
|
|
|
584
664
|
function cloudRunService(args: CloudRunArgs): gcp.cloudrunv2.Service {
|
|
665
|
+
// #1328 — the data gateway has a fixed name: the converge creates it on
|
|
666
|
+
// installs whose stack predates it, and the installer adopts that one.
|
|
667
|
+
const fixedName = fixedCloudRunServiceName("gcp-firebase", env, args.serviceName);
|
|
585
668
|
return new gcp.cloudrunv2.Service(
|
|
586
|
-
`${namePrefix}-${args.serviceName}`,
|
|
669
|
+
args.resourceName ?? `${namePrefix}-${args.serviceName}`,
|
|
587
670
|
{
|
|
671
|
+
...(fixedName ? { name: fixedName } : {}),
|
|
588
672
|
location: region,
|
|
589
673
|
ingress: args.ingress,
|
|
590
674
|
// v0.3.1 — Cloud Run native IAP. With this on, every request
|
|
@@ -604,8 +688,8 @@ function cloudRunService(args: CloudRunArgs): gcp.cloudrunv2.Service {
|
|
|
604
688
|
? { executionEnvironment: args.mediaVolume.executionEnvironment }
|
|
605
689
|
: {}),
|
|
606
690
|
// The admin's media bucket, plus each service's secret files (#806:
|
|
607
|
-
// the
|
|
608
|
-
// upgrade applies to existing installs.
|
|
691
|
+
// the MCP-Auth-Proxy's remote-MCP OAuth client) — both from the
|
|
692
|
+
// contract upgrade applies to existing installs.
|
|
609
693
|
volumes: [
|
|
610
694
|
...(args.mediaVolume?.volumes ?? []),
|
|
611
695
|
...secretFileVolumesTemplate(args.serviceName, env).volumes,
|
|
@@ -625,10 +709,16 @@ function cloudRunService(args: CloudRunArgs): gcp.cloudrunv2.Service {
|
|
|
625
709
|
},
|
|
626
710
|
},
|
|
627
711
|
],
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
712
|
+
// #1328 — the MCP-Auth-Proxy gets no route into the VPC (and so
|
|
713
|
+
// none to Cloud SQL's private IP): SERVICE_VPC_EGRESS.
|
|
714
|
+
...(SERVICE_VPC_EGRESS[args.serviceName]
|
|
715
|
+
? {
|
|
716
|
+
vpcAccess: {
|
|
717
|
+
networkInterfaces: [{ network: network.name, subnetwork: subnet.name }],
|
|
718
|
+
egress: "PRIVATE_RANGES_ONLY",
|
|
719
|
+
},
|
|
720
|
+
}
|
|
721
|
+
: {}),
|
|
632
722
|
},
|
|
633
723
|
},
|
|
634
724
|
{
|
|
@@ -669,30 +759,53 @@ const envContractInputs = {
|
|
|
669
759
|
},
|
|
670
760
|
} as const;
|
|
671
761
|
|
|
672
|
-
//
|
|
673
|
-
// admin's env (the Firebase publisher
|
|
762
|
+
// The data gateway is provisioned first so its name/region can go into the
|
|
763
|
+
// admin's env (the Firebase publisher wires the /api/** rewrite to it).
|
|
764
|
+
// #1328 — a service of its own (`caelo-<env>-data-gateway`); before, the
|
|
765
|
+
// gateway was also the remote-MCP broker.
|
|
674
766
|
const gatewaySvc = cloudRunService({
|
|
675
767
|
serviceName: "gateway",
|
|
676
768
|
minInstances: gatewayMinInstances,
|
|
677
769
|
maxInstances: gatewayMaxInstances,
|
|
678
770
|
memory: "512Mi",
|
|
679
|
-
//
|
|
680
|
-
|
|
681
|
-
//
|
|
682
|
-
//
|
|
683
|
-
|
|
684
|
-
//
|
|
685
|
-
//
|
|
686
|
-
//
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
771
|
+
// Firebase Hosting cuts a rewritten request at 60 s anyway.
|
|
772
|
+
timeout: "300s",
|
|
773
|
+
// #650 — all traffic: `cms-provision staging-domain enable` maps the
|
|
774
|
+
// staging host onto the data gateway (Cloud Run refuses domain-mapped
|
|
775
|
+
// requests under an internal-only ingress), and it is invokable by
|
|
776
|
+
// allUsers anyway (data-gateway-public-invoker below): every /api request
|
|
777
|
+
// passes its rate limits, captcha and honeypot; staging requests pass the
|
|
778
|
+
// staging access gate.
|
|
779
|
+
ingress: "INGRESS_TRAFFIC_ALL",
|
|
780
|
+
contractEnv: [...gatewayEnvContract(envContractInputs), ...poolBudget.env.gateway],
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
// #1328 — the MCP-Auth-Proxy: remote MCP's sign-in broker and its stream to
|
|
784
|
+
// the IAP-protected admin, with no database, no VPC route and an account
|
|
785
|
+
// that reads two secrets. E13 (a) of #763: it is the resource that was the
|
|
786
|
+
// gateway (same logical name), so its service and run.app URL — the address every
|
|
787
|
+
// connector in claude.ai / ChatGPT holds, and the Google sign-in client's
|
|
788
|
+
// registered redirect URI — stay as they were. Always deployed at minimum
|
|
789
|
+
// zero; while remote MCP is not set up it answers a fixed 404 (E14 a).
|
|
790
|
+
const mcpAuthProxySvc = cloudRunService({
|
|
791
|
+
serviceName: "mcp-auth-proxy",
|
|
792
|
+
resourceName: `${namePrefix}-gateway`,
|
|
793
|
+
minInstances: 0,
|
|
794
|
+
maxInstances: DEFAULT_MCP_AUTH_PROXY_MAX_INSTANCES,
|
|
795
|
+
memory: "512Mi",
|
|
796
|
+
// #806 — chat turns stream for minutes (MCP_AUTH_PROXY_TIMEOUT_SECONDS);
|
|
797
|
+
// MCP clients call its run.app URL, never the Firebase rewrite (which
|
|
798
|
+
// buffers streams and cuts at 60 s).
|
|
799
|
+
timeout: `${MCP_AUTH_PROXY_TIMEOUT_SECONDS}s`,
|
|
800
|
+
// Public: MCP clients reach it directly; until #1331 the staging host's
|
|
801
|
+
// domain mapping (#650) still points at this service too, and the proxy
|
|
802
|
+
// forwards that traffic to the data gateway (INTERIM_FORWARD_ORIGIN_ENV).
|
|
691
803
|
ingress: "INGRESS_TRAFFIC_ALL",
|
|
692
804
|
contractEnv: [
|
|
693
|
-
...
|
|
694
|
-
...remoteMcpEnv
|
|
695
|
-
|
|
805
|
+
...mcpAuthProxyEnvContract({ provider: "gcp-firebase", env }),
|
|
806
|
+
...remoteMcpEnv["mcp-auth-proxy"],
|
|
807
|
+
// FIXME(issue #1331): goes with the staging cutover.
|
|
808
|
+
{ name: INTERIM_FORWARD_ORIGIN_ENV, value: gatewaySvc.uri },
|
|
696
809
|
],
|
|
697
810
|
});
|
|
698
811
|
|
|
@@ -751,7 +864,7 @@ const adminSvc = cloudRunService({
|
|
|
751
864
|
// authentication remain the real security boundary, exactly as
|
|
752
865
|
// designed.
|
|
753
866
|
new gcp.cloudrunv2.ServiceIamMember(
|
|
754
|
-
`${namePrefix}-gateway-public-invoker`,
|
|
867
|
+
`${namePrefix}-data-gateway-public-invoker`,
|
|
755
868
|
{
|
|
756
869
|
project,
|
|
757
870
|
location: region,
|
|
@@ -762,6 +875,21 @@ new gcp.cloudrunv2.ServiceIamMember(
|
|
|
762
875
|
opts,
|
|
763
876
|
);
|
|
764
877
|
|
|
878
|
+
// #1328 — the MCP-Auth-Proxy: MCP clients sign in and call it without a
|
|
879
|
+
// Google identity of their own. The binding the service had as the gateway,
|
|
880
|
+
// under its old logical name, so it never lapses.
|
|
881
|
+
new gcp.cloudrunv2.ServiceIamMember(
|
|
882
|
+
`${namePrefix}-gateway-public-invoker`,
|
|
883
|
+
{
|
|
884
|
+
project,
|
|
885
|
+
location: region,
|
|
886
|
+
name: mcpAuthProxySvc.name,
|
|
887
|
+
role: "roles/run.invoker",
|
|
888
|
+
member: "allUsers",
|
|
889
|
+
},
|
|
890
|
+
opts,
|
|
891
|
+
);
|
|
892
|
+
|
|
765
893
|
// v0.6.5 — `run.services.get` on the gateway for the admin runtime
|
|
766
894
|
// SA. Required at DEPLOY TIME (not runtime): when the static
|
|
767
895
|
// publisher creates a Firebase Hosting version with a Cloud Run
|
|
@@ -781,7 +909,7 @@ new gcp.cloudrunv2.ServiceIamMember(
|
|
|
781
909
|
// explicit cross-service grant because the admin's runSa is a
|
|
782
910
|
// DIFFERENT-resource caller from the gateway's perspective.
|
|
783
911
|
new gcp.cloudrunv2.ServiceIamMember(
|
|
784
|
-
`${namePrefix}-gateway-viewer-for-admin-sa`,
|
|
912
|
+
`${namePrefix}-data-gateway-viewer-for-admin-sa`,
|
|
785
913
|
{
|
|
786
914
|
project,
|
|
787
915
|
location: region,
|
|
@@ -1110,6 +1238,7 @@ export const providerOut = out.provider;
|
|
|
1110
1238
|
export const environmentOut = out.environment;
|
|
1111
1239
|
export const adminCloudRunUrlOut = adminSvc.uri;
|
|
1112
1240
|
export const gatewayCloudRunUrlOut = gatewaySvc.uri;
|
|
1241
|
+
export const mcpAuthProxyCloudRunUrlOut = mcpAuthProxySvc.uri;
|
|
1113
1242
|
export const adminDomainOut = adminDomain;
|
|
1114
1243
|
export const firebaseSiteIdOut = firebaseSiteId;
|
|
1115
1244
|
export const bootstrapTokenExpiresAtOut = tokenInfo.expiresAt;
|
|
@@ -20,10 +20,11 @@ pulumi config set caelo-self-hosted:ownerEmail me@example.com
|
|
|
20
20
|
# verified and recorded in .caelo/release.json:
|
|
21
21
|
pulumi config set caelo-self-hosted:adminImage ghcr.io/caelo-cms/admin@sha256:<digest>
|
|
22
22
|
pulumi config set caelo-self-hosted:gatewayImage ghcr.io/caelo-cms/gateway@sha256:<digest>
|
|
23
|
+
pulumi config set caelo-self-hosted:mcpAuthProxyImage ghcr.io/caelo-cms/mcp-auth-proxy@sha256:<digest>
|
|
23
24
|
pulumi up
|
|
24
25
|
```
|
|
25
26
|
|
|
26
|
-
Pulumi mints the postgres and role passwords and the KEK, generates `docker-compose.yml` + `Caddyfile` + `bootstrap.sh` + `pending-token.json` under `.caelo/`, starts Postgres, runs the migrations and runs `docker compose up -d`. Point DNS for `<domain>`, `admin.<domain>` and `staging.<domain>` at the host. After the run:
|
|
27
|
+
Pulumi mints the postgres and role passwords and the KEK, generates `docker-compose.yml` + `Caddyfile` + `bootstrap.sh` + `pending-token.json` under `.caelo/`, starts Postgres, runs the migrations and runs `docker compose up -d`. Point DNS for `<domain>`, `admin.<domain>` and `staging.<domain>` at the host. The MCP sign-in service (`caelo-mcp-auth-proxy`) runs without a public host: remote MCP needs an identity proxy in front of the admin, which self-hosted installs do not have yet, so it only answers 404 and Caddy does not expose it. After the run:
|
|
27
28
|
|
|
28
29
|
```bash
|
|
29
30
|
pulumi stack output bootstrapUrl
|
|
@@ -29,6 +29,7 @@ import { generateCaddyfile, selfHostedAdminHost, selfHostedSeedDomains } from ".
|
|
|
29
29
|
import {
|
|
30
30
|
COMPOSE_ADMIN_UPSTREAM,
|
|
31
31
|
COMPOSE_GATEWAY_UPSTREAM,
|
|
32
|
+
COMPOSE_MCP_AUTH_PROXY_UPSTREAM,
|
|
32
33
|
composeProjectName,
|
|
33
34
|
generateDockerCompose,
|
|
34
35
|
SITE_OUTPUT_ROOT,
|
|
@@ -49,6 +50,9 @@ const adminMemory = cfg.get("adminMemory");
|
|
|
49
50
|
// .caelo/release.json; copy those values here.
|
|
50
51
|
const adminImage = cfg.require("adminImage");
|
|
51
52
|
const gatewayImage = cfg.require("gatewayImage");
|
|
53
|
+
// #1328 — the MCP-Auth-Proxy (remote MCP's sign-in service, its own
|
|
54
|
+
// container and its own host `mcp.<domain>`).
|
|
55
|
+
const mcpAuthProxyImage = cfg.require("mcpAuthProxyImage");
|
|
52
56
|
|
|
53
57
|
const composePath = resolve(caeloDir, "docker-compose.yml");
|
|
54
58
|
const caddyPath = resolve(caeloDir, "Caddyfile");
|
|
@@ -80,7 +84,12 @@ const composeYaml = pulumi
|
|
|
80
84
|
resendApiKey: process.env.RESEND_API_KEY,
|
|
81
85
|
diskSize: "20Gi",
|
|
82
86
|
...(adminMemory ? { adminMemory } : {}),
|
|
83
|
-
images: {
|
|
87
|
+
images: {
|
|
88
|
+
mode: "release",
|
|
89
|
+
admin: adminImage,
|
|
90
|
+
gateway: gatewayImage,
|
|
91
|
+
"mcp-auth-proxy": mcpAuthProxyImage,
|
|
92
|
+
},
|
|
84
93
|
ports: { http: 80, https: 443 },
|
|
85
94
|
project: composeProjectName(domain),
|
|
86
95
|
}),
|
|
@@ -95,6 +104,7 @@ const caddyConf = generateCaddyfile({
|
|
|
95
104
|
stagingSiteRoot: `${SITE_OUTPUT_ROOT}/output/staging/current`,
|
|
96
105
|
adminUpstream: COMPOSE_ADMIN_UPSTREAM,
|
|
97
106
|
gatewayUpstream: COMPOSE_GATEWAY_UPSTREAM,
|
|
107
|
+
mcpAuthProxyUpstream: COMPOSE_MCP_AUTH_PROXY_UPSTREAM,
|
|
98
108
|
domains: selfHostedSeedDomains(domain, stagingHost),
|
|
99
109
|
});
|
|
100
110
|
const bootstrapScript = selfHostedBootstrapScript({ agent: false });
|