@caelo-cms/provisioning 0.6.4 → 0.6.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caelo-cms/provisioning",
3
- "version": "0.6.4",
3
+ "version": "0.6.6",
4
4
  "private": false,
5
5
  "license": "MPL-2.0",
6
6
  "description": "Pulumi-driven provisioning for Caelo CMS — `bunx @caelo-cms/provisioning --provider <self-hosted|gcp|aws|azure>` brings up a TLS-served install with Postgres + storage + secrets manager + the admin + the API gateway.",
@@ -38,7 +38,7 @@
38
38
  "prepublishOnly": "tsc -b --force && tsc --project stacks/gcp/tsconfig.json && tsc --project stacks/gcp-firebase/tsconfig.json"
39
39
  },
40
40
  "dependencies": {
41
- "@caelo-cms/shared": "^0.6.4",
41
+ "@caelo-cms/shared": "^0.6.6",
42
42
  "@clack/prompts": "1.3.0",
43
43
  "@pulumi/aws": "^7",
44
44
  "@pulumi/awsx": "^3",
@@ -141,7 +141,13 @@ const caeloSecretKek = pulumi.secret(kekBytes.hex);
141
141
  // Pre-v0.3.2 the wizard prompted for a key + Pulumi provisioned a
142
142
  // Secret + SecretVersion, but the Cloud Run service never read it
143
143
  // (no env-var mount existed). Dead code path removed.
144
- const resendApiKeyConfig = cfg.getSecret("resendApiKey");
144
+ // v0.6.6 — resend-api-key secret + IAM binding removed. The Resend
145
+ // API key now lives in the email_config DB row (set via the Owner UI
146
+ // /security/email/pending flow per email_config_pending.ts), not in
147
+ // Secret Manager. The Pulumi-managed secret + binding were scaffolded
148
+ // in v0.3.0 but never wired to runtime (transport.ts reads from
149
+ // cfg.config.apiKey, never from Secret Manager). Drop to reduce
150
+ // surface area + monthly cost.
145
151
 
146
152
  interface MadeSecret {
147
153
  resource: gcp.secretmanager.Secret;
@@ -167,7 +173,6 @@ const pgSecret = makeSecret("postgres-password", postgresPassword);
167
173
  const csrfSecretRes = makeSecret("csrf-secret", csrfSecret);
168
174
  const cookieSecretRes = makeSecret("cookie-secret", cookieSecret);
169
175
  const kekSecret = makeSecret("secret-kek", caeloSecretKek);
170
- const resendSecretRes = makeSecret("resend-api-key", resendApiKeyConfig ?? null);
171
176
 
172
177
  // =========================================================================
173
178
  // Tier 4 — Cloud SQL Postgres (private IP only; HA configurable)
@@ -264,7 +269,6 @@ for (const made of [
264
269
  { name: "csrf-secret", made: csrfSecretRes },
265
270
  { name: "cookie-secret", made: cookieSecretRes },
266
271
  { name: "secret-kek", made: kekSecret },
267
- { name: "resend-api-key", made: resendSecretRes },
268
272
  ]) {
269
273
  new gcp.secretmanager.SecretIamMember(
270
274
  `${namePrefix}-${made.name}-binding`,
@@ -300,6 +304,35 @@ new gcp.projects.IAMMember(
300
304
  opts,
301
305
  );
302
306
 
307
+ // v0.6.6 — Cloud Run telemetry IAM. When a Cloud Run service is
308
+ // assigned a CUSTOM runtime SA (serviceAccount: runSa.email below),
309
+ // Cloud Run does NOT automatically grant that SA the roles needed
310
+ // for telemetry to flow:
311
+ // - roles/logging.logWriter: container stdout → Cloud Logging
312
+ // - roles/monitoring.metricWriter: CPU/memory metrics → autoscaler
313
+ // The default Compute Engine SA gets these implicitly; our custom
314
+ // runSa needs them explicit. Without these, logs vanish silently and
315
+ // autoscaling decisions degrade. Project-scoped (telemetry endpoints
316
+ // are project-level resources).
317
+ new gcp.projects.IAMMember(
318
+ `${namePrefix}-run-log-writer`,
319
+ {
320
+ project,
321
+ role: "roles/logging.logWriter",
322
+ member: pulumi.interpolate`serviceAccount:${runSa.email}`,
323
+ },
324
+ opts,
325
+ );
326
+ new gcp.projects.IAMMember(
327
+ `${namePrefix}-run-metric-writer`,
328
+ {
329
+ project,
330
+ role: "roles/monitoring.metricWriter",
331
+ member: pulumi.interpolate`serviceAccount:${runSa.email}`,
332
+ },
333
+ opts,
334
+ );
335
+
303
336
  // =========================================================================
304
337
  // Tier 1 — Firebase Hosting site
305
338
  // =========================================================================
@@ -498,6 +531,36 @@ new gcp.cloudrunv2.ServiceIamMember(
498
531
  opts,
499
532
  );
500
533
 
534
+ // v0.6.5 — `run.services.get` on the gateway for the admin runtime
535
+ // SA. Required at DEPLOY TIME (not runtime): when the static
536
+ // publisher creates a Firebase Hosting version with a Cloud Run
537
+ // rewrite target, Firebase's REST API runs an authorization check
538
+ // that the CALLER (the admin SA — see static-publisher-firebase.ts's
539
+ // googleAuthToken via ADC) has read access on the rewrite target.
540
+ // Without this, every Firebase Hosting deploy hits:
541
+ // 403 PERMISSION_DENIED Permission 'run.services.get' denied on
542
+ // resource 'namespaces/<proj>/services/<gateway-svc>'
543
+ //
544
+ // Scope is the gateway service only (not project-wide). The admin
545
+ // runs on its own Cloud Run service AS runSa via the pod-identity
546
+ // assignment below (`serviceAccount: runSa.email` on the service
547
+ // spec) — Cloud Run handles self-invocation implicitly + does NOT
548
+ // require an explicit roles/run.developer binding on the admin
549
+ // service for the runSa to act as itself. The gateway needs the
550
+ // explicit cross-service grant because the admin's runSa is a
551
+ // DIFFERENT-resource caller from the gateway's perspective.
552
+ new gcp.cloudrunv2.ServiceIamMember(
553
+ `${namePrefix}-gateway-viewer-for-admin-sa`,
554
+ {
555
+ project,
556
+ location: region,
557
+ name: gatewaySvc.name,
558
+ role: "roles/run.viewer",
559
+ member: pulumi.interpolate`serviceAccount:${runSa.email}`,
560
+ },
561
+ opts,
562
+ );
563
+
501
564
  // =========================================================================
502
565
  // Admin custom domain — Cloud Run domain mapping
503
566
  // =========================================================================