@caelo-cms/provisioning 0.10.38 → 0.10.39
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 +21 -3
- package/dist/admin-domain.d.ts.map +1 -1
- package/dist/admin-domain.js +88 -16
- package/dist/admin-domain.js.map +1 -1
- package/dist/cert-wait.d.ts +84 -0
- package/dist/cert-wait.d.ts.map +1 -0
- package/dist/cert-wait.js +95 -0
- package/dist/cert-wait.js.map +1 -0
- package/dist/cli.js +146 -23
- package/dist/cli.js.map +1 -1
- package/dist/dns/groups.d.ts +36 -0
- package/dist/dns/groups.d.ts.map +1 -0
- package/dist/dns/groups.js +46 -0
- package/dist/dns/groups.js.map +1 -0
- package/dist/gcloud-components.d.ts +42 -0
- package/dist/gcloud-components.d.ts.map +1 -0
- package/dist/gcloud-components.js +53 -0
- package/dist/gcloud-components.js.map +1 -0
- package/dist/gcloud.d.ts +14 -0
- package/dist/gcloud.d.ts.map +1 -1
- package/dist/gcloud.js +18 -5
- package/dist/gcloud.js.map +1 -1
- package/dist/install-state.d.ts +8 -0
- package/dist/install-state.d.ts.map +1 -1
- package/dist/install-state.js +5 -0
- package/dist/install-state.js.map +1 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +19 -3
- package/dist/lifecycle.js.map +1 -1
- package/dist/redirects-emit.d.ts +0 -13
- package/dist/redirects-emit.d.ts.map +1 -1
- package/dist/redirects-emit.js +19 -0
- package/dist/redirects-emit.js.map +1 -1
- package/dist/regions.d.ts.map +1 -1
- package/dist/regions.js +4 -1
- package/dist/regions.js.map +1 -1
- package/dist/runtime-secrets.d.ts +13 -1
- package/dist/runtime-secrets.d.ts.map +1 -1
- package/dist/runtime-secrets.js +40 -4
- package/dist/runtime-secrets.js.map +1 -1
- package/dist/self-hosted-roles.d.ts.map +1 -1
- package/dist/self-hosted-roles.js +2 -0
- package/dist/self-hosted-roles.js.map +1 -1
- package/dist/stack-contract.d.ts +16 -2
- package/dist/stack-contract.d.ts.map +1 -1
- package/dist/stack-contract.js +24 -1
- package/dist/stack-contract.js.map +1 -1
- package/dist/wizard.d.ts +5 -19
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +45 -1
- package/dist/wizard.js.map +1 -1
- package/dist/wizards/gcp-pulumi.d.ts +2 -0
- package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
- package/dist/wizards/gcp-pulumi.js +6 -0
- package/dist/wizards/gcp-pulumi.js.map +1 -1
- package/dist/wizards/gcp.d.ts.map +1 -1
- package/dist/wizards/gcp.js +129 -112
- package/dist/wizards/gcp.js.map +1 -1
- package/package.json +3 -3
- package/stacks/gcp/index.ts +20 -3
- package/stacks/gcp-firebase/index.ts +20 -5
- package/stacks/self-hosted/index.ts +3 -1
package/stacks/gcp/index.ts
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
type CloudRunEnvVar,
|
|
39
39
|
type CloudRunSlug,
|
|
40
40
|
databaseUrls,
|
|
41
|
+
defaultStagingHost,
|
|
41
42
|
gatewayEnvContract,
|
|
42
43
|
type RuntimeSecret,
|
|
43
44
|
runtimeSecretBindings,
|
|
@@ -46,6 +47,8 @@ import {
|
|
|
46
47
|
|
|
47
48
|
const cfg = new pulumi.Config();
|
|
48
49
|
const domain = cfg.require("domain");
|
|
50
|
+
// #650 — the protected staging site's host (wizard / `--staging-domain`).
|
|
51
|
+
const stagingHost = cfg.get("stagingDomain") ?? defaultStagingHost(domain);
|
|
49
52
|
const ownerEmail = cfg.require("ownerEmail");
|
|
50
53
|
const project = cfg.require("project");
|
|
51
54
|
// #607 — chosen by the operator in the wizard and fixed after install; no
|
|
@@ -245,6 +248,7 @@ const runtimeSecretIds: Record<RuntimeSecret, pulumi.Input<string>> = {
|
|
|
245
248
|
"secret-kek": kekSecret.resource.secretId,
|
|
246
249
|
"internal-secret": gcpSecretId(env, "internal-secret"),
|
|
247
250
|
"tool-approval-secret": gcpSecretId(env, "tool-approval-secret"),
|
|
251
|
+
"staging-gate-secret": gcpSecretId(env, "staging-gate-secret"),
|
|
248
252
|
"public-role-password": gcpSecretId(env, "public-role-password"),
|
|
249
253
|
"gateway-role-password": gcpSecretId(env, "gateway-role-password"),
|
|
250
254
|
};
|
|
@@ -645,6 +649,7 @@ const envContractInputs = {
|
|
|
645
649
|
env,
|
|
646
650
|
domain,
|
|
647
651
|
region,
|
|
652
|
+
stagingHost,
|
|
648
653
|
databaseUrls: {
|
|
649
654
|
admin: dbUrls.admin,
|
|
650
655
|
publicAdmin: dbUrls.publicAdmin,
|
|
@@ -1015,17 +1020,29 @@ const urlMap = new gcp.compute.URLMap(
|
|
|
1015
1020
|
opts,
|
|
1016
1021
|
);
|
|
1017
1022
|
|
|
1018
|
-
// Managed TLS cert covering both hostnames.
|
|
1019
|
-
// the certificate's SAN list grows by one entry vs the prior version.
|
|
1023
|
+
// Managed TLS cert covering both hostnames.
|
|
1020
1024
|
const managedCert = new gcp.compute.ManagedSslCertificate(
|
|
1021
1025
|
`${namePrefix}-cert`,
|
|
1022
1026
|
{ managed: { domains: [domain, adminDomain] } },
|
|
1023
1027
|
opts,
|
|
1024
1028
|
);
|
|
1025
1029
|
|
|
1030
|
+
// The admin's own certificate. A multi-domain managed certificate is only
|
|
1031
|
+
// served once EVERY domain on it validates, and the main domain validates
|
|
1032
|
+
// only after its A record points here — which an operator with a live site
|
|
1033
|
+
// does at go-live, not during the install. With this one the admin gets
|
|
1034
|
+
// HTTPS as soon as admin.<domain> resolves. The combined certificate above
|
|
1035
|
+
// stays (replacing it would re-issue the live site's certificate); the load
|
|
1036
|
+
// balancer picks whichever ACTIVE certificate matches the requested host.
|
|
1037
|
+
const adminCert = new gcp.compute.ManagedSslCertificate(
|
|
1038
|
+
`${namePrefix}-admin-cert`,
|
|
1039
|
+
{ managed: { domains: [adminDomain] } },
|
|
1040
|
+
opts,
|
|
1041
|
+
);
|
|
1042
|
+
|
|
1026
1043
|
const httpsProxy = new gcp.compute.TargetHttpsProxy(
|
|
1027
1044
|
`${namePrefix}-https-proxy`,
|
|
1028
|
-
{ urlMap: urlMap.id, sslCertificates: [managedCert.id] },
|
|
1045
|
+
{ urlMap: urlMap.id, sslCertificates: [adminCert.id, managedCert.id] },
|
|
1029
1046
|
opts,
|
|
1030
1047
|
);
|
|
1031
1048
|
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
type CloudRunEnvVar,
|
|
46
46
|
type CloudRunSlug,
|
|
47
47
|
databaseUrls,
|
|
48
|
+
defaultStagingHost,
|
|
48
49
|
gatewayEnvContract,
|
|
49
50
|
type RuntimeSecret,
|
|
50
51
|
runtimeSecretBindings,
|
|
@@ -52,6 +53,8 @@ import {
|
|
|
52
53
|
|
|
53
54
|
const cfg = new pulumi.Config();
|
|
54
55
|
const domain = cfg.require("domain");
|
|
56
|
+
// #650 — the protected staging site's host (wizard / `--staging-domain`).
|
|
57
|
+
const stagingHost = cfg.get("stagingDomain") ?? defaultStagingHost(domain);
|
|
55
58
|
const ownerEmail = cfg.require("ownerEmail");
|
|
56
59
|
const project = cfg.require("project");
|
|
57
60
|
// #607 — chosen by the operator in the wizard and fixed after install; no
|
|
@@ -219,6 +222,7 @@ const runtimeSecretIds: Record<RuntimeSecret, pulumi.Input<string>> = {
|
|
|
219
222
|
"secret-kek": kekSecret.resource.secretId,
|
|
220
223
|
"internal-secret": gcpSecretId(env, "internal-secret"),
|
|
221
224
|
"tool-approval-secret": gcpSecretId(env, "tool-approval-secret"),
|
|
225
|
+
"staging-gate-secret": gcpSecretId(env, "staging-gate-secret"),
|
|
222
226
|
"public-role-password": gcpSecretId(env, "public-role-password"),
|
|
223
227
|
"gateway-role-password": gcpSecretId(env, "gateway-role-password"),
|
|
224
228
|
};
|
|
@@ -590,6 +594,7 @@ const envContractInputs = {
|
|
|
590
594
|
env,
|
|
591
595
|
domain,
|
|
592
596
|
region,
|
|
597
|
+
stagingHost,
|
|
593
598
|
databaseUrls: {
|
|
594
599
|
admin: dbUrls.admin,
|
|
595
600
|
publicAdmin: dbUrls.publicAdmin,
|
|
@@ -606,10 +611,14 @@ const gatewaySvc = cloudRunService({
|
|
|
606
611
|
maxInstances: 100,
|
|
607
612
|
memory: "512Mi",
|
|
608
613
|
timeout: "60s",
|
|
609
|
-
//
|
|
610
|
-
//
|
|
611
|
-
//
|
|
612
|
-
ingress:
|
|
614
|
+
// #650 — all traffic: the gateway also serves staging.<domain> through
|
|
615
|
+
// a Cloud Run domain mapping (`cms-provision staging-domain enable`),
|
|
616
|
+
// and Cloud Run refuses domain-mapped requests under an internal-only
|
|
617
|
+
// ingress. Exposure is unchanged in substance: the service was already
|
|
618
|
+
// invokable by allUsers (gateway-public-invoker below) and every /api
|
|
619
|
+
// request passes its rate limits, captcha and honeypot; staging requests
|
|
620
|
+
// pass the staging access gate.
|
|
621
|
+
ingress: "INGRESS_TRAFFIC_ALL",
|
|
613
622
|
contractEnv: gatewayEnvContract(envContractInputs),
|
|
614
623
|
});
|
|
615
624
|
|
|
@@ -940,12 +949,18 @@ const dnsRecords: pulumi.Output<DnsRecord[]> = pulumi
|
|
|
940
949
|
// groups; each group has a list of `desired` records the operator
|
|
941
950
|
// creates and `discovered` records currently in DNS. We surface the
|
|
942
951
|
// `desired` set so the operator knows what to put in the registrar.
|
|
952
|
+
// Each record carries its own name: besides the apex A records Firebase
|
|
953
|
+
// asks for TXT records, some on `_acme-challenge.<domain>`, which let it
|
|
954
|
+
// issue the certificate before the apex moves. Records Firebase wants
|
|
955
|
+
// REMOVED (the old site's A records) are not records to add; replacing
|
|
956
|
+
// the apex records at go-live drops them.
|
|
943
957
|
const apex = firebaseUpdates?.[0];
|
|
944
958
|
if (apex) {
|
|
945
959
|
for (const desired of apex.desireds ?? []) {
|
|
946
960
|
for (const v of desired.records ?? []) {
|
|
961
|
+
if (v.requiredAction === "REMOVE") continue;
|
|
947
962
|
out.push({
|
|
948
|
-
hostname: domain,
|
|
963
|
+
hostname: (v.domainName ?? desired.domainName ?? domain).replace(/\.$/, ""),
|
|
949
964
|
type: (v.type ?? "A") as DnsRecord["type"],
|
|
950
965
|
value: v.rdata ?? "",
|
|
951
966
|
purpose: "Public site → Firebase Hosting CDN",
|
|
@@ -29,6 +29,8 @@ import { generateDockerCompose } from "../../dist/compose.js";
|
|
|
29
29
|
|
|
30
30
|
const cfg = new pulumi.Config();
|
|
31
31
|
const domain = cfg.require("domain");
|
|
32
|
+
// #650 — the staging site's host (install setting, default staging.<domain>).
|
|
33
|
+
const stagingHost = cfg.get("stagingDomain") ?? `staging.${domain}`;
|
|
32
34
|
const ownerEmail = cfg.require("ownerEmail");
|
|
33
35
|
const caeloDir = cfg.get("caeloDir") ?? "./.caelo";
|
|
34
36
|
// #553 — same knob as every adapter; undefined = stack-contract default.
|
|
@@ -81,7 +83,7 @@ const caddyConf = generateCaddyfile({
|
|
|
81
83
|
domains: [
|
|
82
84
|
{ hostname: domain, kind: "admin", env: "production" as const },
|
|
83
85
|
{ hostname: domain, kind: "public", env: "production" as const },
|
|
84
|
-
{ hostname:
|
|
86
|
+
{ hostname: stagingHost, kind: "public", env: "staging" as const },
|
|
85
87
|
],
|
|
86
88
|
});
|
|
87
89
|
|