@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
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* `.caelo/release.json` is the install metadata for self-hosted (the cloud
|
|
7
7
|
* providers keep theirs in `~/.caelo-<id>/install.json`): the release
|
|
8
|
-
* version, the digest-pinned
|
|
9
|
-
*
|
|
8
|
+
* version, the digest-pinned image references the Compose file runs (admin,
|
|
9
|
+
* gateway, and since #1328 the MCP-Auth-Proxy), and a short history of installs/upgrades/rollbacks. It holds no
|
|
10
10
|
* secrets (config.json does), so it is safe to read from tooling and
|
|
11
11
|
* backups; writes refuse secret material like install.json's do.
|
|
12
12
|
*
|
|
@@ -52,7 +52,16 @@ export function releasePath(caeloDir) {
|
|
|
52
52
|
}
|
|
53
53
|
/** The images of a recorded release, as the Compose generator takes them. */
|
|
54
54
|
export function releaseImages(release) {
|
|
55
|
-
return { mode: "release",
|
|
55
|
+
return { mode: "release", ...release.images };
|
|
56
|
+
}
|
|
57
|
+
/** The image references of `images`, as release.json stores them. */
|
|
58
|
+
function recordedImages(images) {
|
|
59
|
+
const proxy = images["mcp-auth-proxy"];
|
|
60
|
+
return {
|
|
61
|
+
admin: images.admin,
|
|
62
|
+
gateway: images.gateway,
|
|
63
|
+
...(proxy !== undefined ? { "mcp-auth-proxy": proxy } : {}),
|
|
64
|
+
};
|
|
56
65
|
}
|
|
57
66
|
/**
|
|
58
67
|
* The install's recorded release, or null when none is recorded (a dev-mode
|
|
@@ -66,14 +75,16 @@ export function readRelease(caeloDir) {
|
|
|
66
75
|
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
67
76
|
const admin = raw.images?.admin ?? "";
|
|
68
77
|
const gateway = raw.images?.gateway ?? "";
|
|
78
|
+
const proxy = raw.images?.["mcp-auth-proxy"];
|
|
69
79
|
if (typeof raw.version !== "string" ||
|
|
70
80
|
!ghcrImageDigest("admin", admin) ||
|
|
71
|
-
!ghcrImageDigest("gateway", gateway)
|
|
81
|
+
!ghcrImageDigest("gateway", gateway) ||
|
|
82
|
+
(proxy !== undefined && !ghcrImageDigest("mcp-auth-proxy", proxy))) {
|
|
72
83
|
throw new Error(`${path} is malformed (needs version + digest-pinned ghcr.io/caelo-cms images); fix it or re-run \`${selfCommand("upgrade", "--version", "<x.y.z>")}\`.`);
|
|
73
84
|
}
|
|
74
85
|
return {
|
|
75
86
|
version: raw.version,
|
|
76
|
-
images: { admin, gateway },
|
|
87
|
+
images: { admin, gateway, ...(proxy !== undefined ? { "mcp-auth-proxy": proxy } : {}) },
|
|
77
88
|
installedAt: raw.installedAt ?? "",
|
|
78
89
|
history: Array.isArray(raw.history) ? raw.history : [],
|
|
79
90
|
};
|
|
@@ -87,7 +98,7 @@ export function recordRelease(caeloDir, next, entry, now = new Date()) {
|
|
|
87
98
|
const at = now.toISOString();
|
|
88
99
|
const record = {
|
|
89
100
|
version: next.version,
|
|
90
|
-
images:
|
|
101
|
+
images: recordedImages(next.images),
|
|
91
102
|
installedAt: prior && prior.version === next.version && entry.outcome === "rolled-back"
|
|
92
103
|
? prior.installedAt
|
|
93
104
|
: at,
|
|
@@ -102,7 +113,7 @@ export function recordRollback(caeloDir, current, attempted, detail, now = new D
|
|
|
102
113
|
recordRelease(caeloDir, { version: current.version, images: releaseImages(current) }, { from: current.version, to: attempted, outcome: "rolled-back", detail }, now);
|
|
103
114
|
}
|
|
104
115
|
/**
|
|
105
|
-
* Resolve
|
|
116
|
+
* Resolve every release image of `tag` (RELEASE_SERVICES) in GHCR to digests,
|
|
106
117
|
* then cosign-verify each digest against the Caelo release workflow
|
|
107
118
|
* identity (unless `skipVerify`, the escape hatch for forks). The returned
|
|
108
119
|
* references are digest-pinned, so what was verified is exactly what runs.
|
|
@@ -112,6 +123,14 @@ export async function resolveVerifiedRelease(tag, deps) {
|
|
|
112
123
|
for (const service of RELEASE_SERVICES) {
|
|
113
124
|
deps.onProgress?.(`Resolving ${GHCR_REGISTRY}/${GHCR_NAMESPACE}/${service}:${tag}`);
|
|
114
125
|
const r = await resolveRegistryDigest(GHCR_REGISTRY, `${GHCR_NAMESPACE}/${service}`, tag, deps.fetchImpl);
|
|
126
|
+
if (!r.ok && r.notFound && service === "mcp-auth-proxy") {
|
|
127
|
+
// #1328 — releases from before the MCP-Auth-Proxy ship no image of it,
|
|
128
|
+
// and they stay installable and rollback targets: their Compose file
|
|
129
|
+
// simply has no proxy (ReleaseImages models the absence). Only a
|
|
130
|
+
// registry verdict that the tag does not exist means that; an outage
|
|
131
|
+
// still fails below, never silently installs a release without it.
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
115
134
|
if (!r.ok) {
|
|
116
135
|
return {
|
|
117
136
|
ok: false,
|
|
@@ -121,10 +140,12 @@ export async function resolveVerifiedRelease(tag, deps) {
|
|
|
121
140
|
}
|
|
122
141
|
refs[service] = ghcrImageRef(service, r.digest);
|
|
123
142
|
}
|
|
143
|
+
const proxy = refs["mcp-auth-proxy"];
|
|
124
144
|
const images = {
|
|
125
145
|
mode: "release",
|
|
126
146
|
admin: refs.admin ?? "",
|
|
127
147
|
gateway: refs.gateway ?? "",
|
|
148
|
+
...(proxy ? { "mcp-auth-proxy": proxy } : {}),
|
|
128
149
|
};
|
|
129
150
|
if (deps.skipVerify)
|
|
130
151
|
return { ok: true, images };
|
|
@@ -138,12 +159,15 @@ export async function resolveVerifiedRelease(tag, deps) {
|
|
|
138
159
|
};
|
|
139
160
|
}
|
|
140
161
|
for (const service of RELEASE_SERVICES) {
|
|
162
|
+
const ref = images[service];
|
|
163
|
+
if (ref === undefined)
|
|
164
|
+
continue;
|
|
141
165
|
deps.onProgress?.(`Verifying the signature of ${service}`);
|
|
142
|
-
const v = await deps.runner.run(cosignVerifyArgv(
|
|
166
|
+
const v = await deps.runner.run(cosignVerifyArgv(ref));
|
|
143
167
|
if (v.exitCode !== 0) {
|
|
144
168
|
return {
|
|
145
169
|
ok: false,
|
|
146
|
-
error: `cosign verify FAILED for ${
|
|
170
|
+
error: `cosign verify FAILED for ${ref}: its signature does not match the Caelo release workflow.\n` +
|
|
147
171
|
"Either the registry was compromised, the image is a fork's, or sigstore had an outage (retry).\n" +
|
|
148
172
|
`cosign: ${v.stderr.trim().slice(0, 500)}`,
|
|
149
173
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-hosted-release.js","sourceRoot":"","sources":["../src/self-hosted-release.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,YAAY,EAAsB,MAAM,cAAc,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,gBAAgB,
|
|
1
|
+
{"version":3,"file":"self-hosted-release.js","sourceRoot":"","sources":["../src/self-hosted-release.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
* as the Postgres superuser BEFORE it writes the new Compose file: it
|
|
12
12
|
* creates missing roles and databases and sets each role's password to the
|
|
13
13
|
* configured one. It also drops the former `gateway_role` (#635: the
|
|
14
|
-
* gateway has no cms_admin login), with whatever it still holds
|
|
15
|
-
*
|
|
14
|
+
* gateway has no cms_admin login), with whatever it still holds, and
|
|
15
|
+
* (#1329) creates the staging database `cms_public_staging` with the
|
|
16
|
+
* staging gateway's login `public_staging_role` on an install from before
|
|
17
|
+
* it. Every statement is idempotent.
|
|
16
18
|
*
|
|
17
19
|
* Passwords travel on psql's stdin, never on argv.
|
|
18
20
|
*/
|
|
@@ -24,6 +26,34 @@ import type { RolePasswords } from "./compose.js";
|
|
|
24
26
|
* append events, write the heartbeat (0270) and its own audit rows.
|
|
25
27
|
*/
|
|
26
28
|
export declare const AGENT_DB_ROLE = "caelo_agent";
|
|
29
|
+
/**
|
|
30
|
+
* #1338 (gateway hardening H3) — what bounds public_role, the gateway's
|
|
31
|
+
* login, on the database: at most this many connections, no statement or
|
|
32
|
+
* idle transaction that runs away, little sort memory per query. The same
|
|
33
|
+
* values as packages/migrations/src/bootstrap.sh and the cms_admin
|
|
34
|
+
* migration that sets them where admin_role may (Cloud SQL); the role audit
|
|
35
|
+
* (packages/migrations role-audit.ts) refuses an install without them.
|
|
36
|
+
* Self-hosted admin_role has no CREATEROLE, so the superuser applies them
|
|
37
|
+
* here — on the volume's first start (bootstrap.sh), on every `up`, and
|
|
38
|
+
* before the migrations of every upgrade ({@link preMigrationRolesScript}).
|
|
39
|
+
* Since #1329 the staging gateway's public_staging_role carries the same.
|
|
40
|
+
*/
|
|
41
|
+
export declare const PUBLIC_ROLE_LIMITS: {
|
|
42
|
+
readonly connectionLimit: 30;
|
|
43
|
+
readonly statementTimeout: "5s";
|
|
44
|
+
readonly idleInTransactionSessionTimeout: "15s";
|
|
45
|
+
readonly workMem: "1MB";
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The psql script (superuser) the self-hosted upgrade runs BEFORE the
|
|
49
|
+
* migrations: the gateway logins' {@link PUBLIC_ROLE_LIMITS} (#1338) and
|
|
50
|
+
* (#1329) the staging database with its login. The migrations' role audit
|
|
51
|
+
* refuses either gateway login without its limits, and the
|
|
52
|
+
* cms_public_staging run needs the database; the full convergence must
|
|
53
|
+
* wait until after them (it drops roles a migration retired). Fails when
|
|
54
|
+
* public_role does not exist — the install's roles were never created.
|
|
55
|
+
*/
|
|
56
|
+
export declare function preMigrationRolesScript(stagingPassword: string): string;
|
|
27
57
|
/**
|
|
28
58
|
* The psql script (run as the superuser, connected to any database) that
|
|
29
59
|
* brings roles and databases to the configured state.
|
|
@@ -47,6 +77,17 @@ export type SuperuserPsql = (script: string) => Promise<{
|
|
|
47
77
|
exitCode: number;
|
|
48
78
|
stderr: string;
|
|
49
79
|
}>;
|
|
80
|
+
/**
|
|
81
|
+
* Apply {@link preMigrationRolesScript} through the running Postgres
|
|
82
|
+
* container. Unlike {@link convergeSelfHostedRoles} a stopped database is a
|
|
83
|
+
* failure: the upgrade runs it right before migrations that need it.
|
|
84
|
+
*/
|
|
85
|
+
export declare function applyPreMigrationRoles(deps: {
|
|
86
|
+
readonly probe: () => Promise<boolean>;
|
|
87
|
+
readonly psql: SuperuserPsql;
|
|
88
|
+
/** #1329 — public_staging_role's password from `.caelo/config.json`. */
|
|
89
|
+
readonly stagingPassword: string;
|
|
90
|
+
}): Promise<ConvergeOutcome>;
|
|
50
91
|
export type ConvergeOutcome = {
|
|
51
92
|
readonly ok: true;
|
|
52
93
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-hosted-roles.d.ts","sourceRoot":"","sources":["../src/self-hosted-roles.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"self-hosted-roles.d.ts","sourceRoot":"","sources":["../src/self-hosted-roles.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAOlD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAS3C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB;;;;;CAKrB,CAAC;AAmCX;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAOvE;AAmDD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,aAAa,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAU9F;AAUD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAqBnF;AAED,kFAAkF;AAClF,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9F;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,wEAAwE;IACxE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,eAAe,CAAC,CAO3B;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE;AACvB,+EAA+E;GAC7E;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE;IACJ,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC,GACA,OAAO,CAAC,eAAe,CAAC,CAO1B;AAED,+DAA+D;AAC/D,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACxF;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG,UAAU,CAoBtF"}
|
|
@@ -11,7 +11,72 @@ function literal(s) {
|
|
|
11
11
|
*/
|
|
12
12
|
export const AGENT_DB_ROLE = "caelo_agent";
|
|
13
13
|
/** The application roles bootstrap.sh and the convergence create. */
|
|
14
|
-
const APP_ROLES = ["admin_role", "public_role"];
|
|
14
|
+
const APP_ROLES = ["admin_role", "public_role", "public_staging_role"];
|
|
15
|
+
/** #1329 — the gateway logins that carry {@link PUBLIC_ROLE_LIMITS}: the live and the staging one. */
|
|
16
|
+
const GATEWAY_LOGINS = ["public_role", "public_staging_role"];
|
|
17
|
+
/**
|
|
18
|
+
* #1338 (gateway hardening H3) — what bounds public_role, the gateway's
|
|
19
|
+
* login, on the database: at most this many connections, no statement or
|
|
20
|
+
* idle transaction that runs away, little sort memory per query. The same
|
|
21
|
+
* values as packages/migrations/src/bootstrap.sh and the cms_admin
|
|
22
|
+
* migration that sets them where admin_role may (Cloud SQL); the role audit
|
|
23
|
+
* (packages/migrations role-audit.ts) refuses an install without them.
|
|
24
|
+
* Self-hosted admin_role has no CREATEROLE, so the superuser applies them
|
|
25
|
+
* here — on the volume's first start (bootstrap.sh), on every `up`, and
|
|
26
|
+
* before the migrations of every upgrade ({@link preMigrationRolesScript}).
|
|
27
|
+
* Since #1329 the staging gateway's public_staging_role carries the same.
|
|
28
|
+
*/
|
|
29
|
+
export const PUBLIC_ROLE_LIMITS = {
|
|
30
|
+
connectionLimit: 30,
|
|
31
|
+
statementTimeout: "5s",
|
|
32
|
+
idleInTransactionSessionTimeout: "15s",
|
|
33
|
+
workMem: "1MB",
|
|
34
|
+
};
|
|
35
|
+
/** The statements that apply {@link PUBLIC_ROLE_LIMITS} to both gateway logins (idempotent). */
|
|
36
|
+
function publicRoleLimitsSql() {
|
|
37
|
+
const l = PUBLIC_ROLE_LIMITS;
|
|
38
|
+
return GATEWAY_LOGINS.flatMap((role) => [
|
|
39
|
+
`ALTER ROLE ${role} CONNECTION LIMIT ${l.connectionLimit};`,
|
|
40
|
+
`ALTER ROLE ${role} SET statement_timeout = '${l.statementTimeout}';`,
|
|
41
|
+
`ALTER ROLE ${role} SET idle_in_transaction_session_timeout = '${l.idleInTransactionSessionTimeout}';`,
|
|
42
|
+
`ALTER ROLE ${role} SET work_mem = '${l.workMem}';`,
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* #1329 — the staging database and its gateway login, with each gateway
|
|
47
|
+
* login on its own database only (the same as bootstrap.sh and cms_admin
|
|
48
|
+
* migration 0530). Idempotent: an install from before #1329 gets both, an
|
|
49
|
+
* install that has them gets the password re-applied.
|
|
50
|
+
*/
|
|
51
|
+
function stagingDatabaseSql(password) {
|
|
52
|
+
return [
|
|
53
|
+
"SELECT 'CREATE ROLE public_staging_role NOINHERIT LOGIN' WHERE NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'public_staging_role') \\gexec",
|
|
54
|
+
`ALTER ROLE public_staging_role WITH LOGIN PASSWORD ${password("public_staging_role")};`,
|
|
55
|
+
"SELECT 'CREATE DATABASE cms_public_staging OWNER admin_role' WHERE NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'cms_public_staging') \\gexec",
|
|
56
|
+
"REVOKE ALL ON DATABASE cms_public_staging FROM PUBLIC;",
|
|
57
|
+
"GRANT CONNECT ON DATABASE cms_public_staging TO public_staging_role, admin_role;",
|
|
58
|
+
"REVOKE ALL ON DATABASE cms_public_staging FROM public_role;",
|
|
59
|
+
"REVOKE ALL ON DATABASE cms_public FROM public_staging_role;",
|
|
60
|
+
"REVOKE ALL ON DATABASE cms_admin FROM public_staging_role;",
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The psql script (superuser) the self-hosted upgrade runs BEFORE the
|
|
65
|
+
* migrations: the gateway logins' {@link PUBLIC_ROLE_LIMITS} (#1338) and
|
|
66
|
+
* (#1329) the staging database with its login. The migrations' role audit
|
|
67
|
+
* refuses either gateway login without its limits, and the
|
|
68
|
+
* cms_public_staging run needs the database; the full convergence must
|
|
69
|
+
* wait until after them (it drops roles a migration retired). Fails when
|
|
70
|
+
* public_role does not exist — the install's roles were never created.
|
|
71
|
+
*/
|
|
72
|
+
export function preMigrationRolesScript(stagingPassword) {
|
|
73
|
+
return [
|
|
74
|
+
"\\set ON_ERROR_STOP on",
|
|
75
|
+
...stagingDatabaseSql(() => literal(stagingPassword)),
|
|
76
|
+
...publicRoleLimitsSql(),
|
|
77
|
+
"",
|
|
78
|
+
].join("\n");
|
|
79
|
+
}
|
|
15
80
|
/**
|
|
16
81
|
* The convergence SQL (psql, as the superuser, connected to any database).
|
|
17
82
|
* `password` renders each role's password; `agent` adds the agent's login.
|
|
@@ -23,6 +88,7 @@ function convergenceSql(password, agent) {
|
|
|
23
88
|
`SELECT 'CREATE ROLE ${role} NOINHERIT LOGIN' WHERE NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${role}') \\gexec`,
|
|
24
89
|
`ALTER ROLE ${role} WITH LOGIN PASSWORD ${password(role)};`,
|
|
25
90
|
]),
|
|
91
|
+
...publicRoleLimitsSql(),
|
|
26
92
|
// The upgrader's role (migration 0267 creates it only with CREATEROLE,
|
|
27
93
|
// which the self-hosted admin_role lacks).
|
|
28
94
|
"SELECT 'CREATE ROLE platform_updater NOLOGIN' WHERE NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'platform_updater') \\gexec",
|
|
@@ -41,11 +107,15 @@ function convergenceSql(password, agent) {
|
|
|
41
107
|
"REVOKE ALL ON DATABASE cms_public FROM PUBLIC;",
|
|
42
108
|
"GRANT CONNECT ON DATABASE cms_admin TO admin_role;",
|
|
43
109
|
"GRANT CONNECT ON DATABASE cms_public TO public_role, admin_role;",
|
|
110
|
+
// #1329 — after the other two databases exist: its revokes name them.
|
|
111
|
+
...stagingDatabaseSql(password),
|
|
44
112
|
// #635 — the gateway's former cms_admin login goes, with whatever it
|
|
45
113
|
// still holds in either database (the superuser may drop what
|
|
46
114
|
// migration 0285 could only revoke).
|
|
47
115
|
"\\connect cms_public",
|
|
48
116
|
"DO $$ BEGIN IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'gateway_role') THEN DROP OWNED BY gateway_role; END IF; END $$;",
|
|
117
|
+
"\\connect cms_public_staging",
|
|
118
|
+
"DO $$ BEGIN IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'gateway_role') THEN DROP OWNED BY gateway_role; END IF; END $$;",
|
|
49
119
|
"\\connect cms_admin",
|
|
50
120
|
"DO $$ BEGIN IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'gateway_role') THEN DROP OWNED BY gateway_role; END IF; END $$;",
|
|
51
121
|
"DO $$ BEGIN IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'gateway_role') THEN DROP ROLE gateway_role; END IF; END $$;",
|
|
@@ -65,6 +135,7 @@ export function roleConvergenceScript(passwords, agentPassword) {
|
|
|
65
135
|
const byRole = {
|
|
66
136
|
admin_role: passwords.admin,
|
|
67
137
|
public_role: passwords.public,
|
|
138
|
+
public_staging_role: passwords.publicStaging,
|
|
68
139
|
};
|
|
69
140
|
return convergenceSql((role) => literal(role === AGENT_DB_ROLE ? (agentPassword ?? "") : byRole[role]), agentPassword !== undefined);
|
|
70
141
|
}
|
|
@@ -72,6 +143,7 @@ export function roleConvergenceScript(passwords, agentPassword) {
|
|
|
72
143
|
const PASSWORD_ENV = {
|
|
73
144
|
admin_role: "ADMIN_ROLE_PASSWORD",
|
|
74
145
|
public_role: "PUBLIC_ROLE_PASSWORD",
|
|
146
|
+
public_staging_role: "PUBLIC_STAGING_ROLE_PASSWORD",
|
|
75
147
|
[AGENT_DB_ROLE]: "AGENT_ROLE_PASSWORD",
|
|
76
148
|
};
|
|
77
149
|
/**
|
|
@@ -104,6 +176,20 @@ ${variables}
|
|
|
104
176
|
${convergenceSql((role) => `:'${role}_pw'`, opts.agent)}CAELO_SQL
|
|
105
177
|
`;
|
|
106
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* Apply {@link preMigrationRolesScript} through the running Postgres
|
|
181
|
+
* container. Unlike {@link convergeSelfHostedRoles} a stopped database is a
|
|
182
|
+
* failure: the upgrade runs it right before migrations that need it.
|
|
183
|
+
*/
|
|
184
|
+
export async function applyPreMigrationRoles(deps) {
|
|
185
|
+
if (!(await deps.probe())) {
|
|
186
|
+
return { ok: false, reachable: false, error: "the Postgres container is not running" };
|
|
187
|
+
}
|
|
188
|
+
const r = await deps.psql(preMigrationRolesScript(deps.stagingPassword));
|
|
189
|
+
if (r.exitCode === 0)
|
|
190
|
+
return { ok: true };
|
|
191
|
+
return { ok: false, reachable: true, error: r.stderr.trim() || `psql exited ${r.exitCode}` };
|
|
192
|
+
}
|
|
107
193
|
/**
|
|
108
194
|
* Apply {@link roleConvergenceScript}. `probe` says whether the database is
|
|
109
195
|
* up; when it is not, nothing is attempted and the caller decides whether
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-hosted-roles.js","sourceRoot":"","sources":["../src/self-hosted-roles.ts"],"names":[],"mappings":"AAAA,mCAAmC;
|
|
1
|
+
{"version":3,"file":"self-hosted-roles.js","sourceRoot":"","sources":["../src/self-hosted-roles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read the interval `init` recorded in a `.caelo/config.json`.
|
|
3
|
+
*
|
|
4
|
+
* @param configPath - the install's `config.json`.
|
|
5
|
+
* @returns the recorded minutes, or undefined when there is no config.json
|
|
6
|
+
* (a Pulumi-only install) or it records no interval (the default).
|
|
7
|
+
* @throws when the file is not JSON or the recorded value is out of bounds.
|
|
8
|
+
*/
|
|
9
|
+
export declare function recordedSchedulerIntervalMinutes(configPath: string): number | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* The interval the self-hosted Pulumi stack renders into the Compose file.
|
|
12
|
+
*
|
|
13
|
+
* @param pulumiValue - `caelo-self-hosted:schedulerIntervalMinutes`, if set.
|
|
14
|
+
* @param recorded - what {@link recordedSchedulerIntervalMinutes} read.
|
|
15
|
+
* @param configPath - named in the refusal.
|
|
16
|
+
* @returns the minutes to render; undefined means neither source sets one
|
|
17
|
+
* (the generator's default).
|
|
18
|
+
* @throws when both are set and differ.
|
|
19
|
+
*/
|
|
20
|
+
export declare function selfHostedSchedulerIntervalMinutes(pulumiValue: number | undefined, recorded: number | undefined, configPath: string): number | undefined;
|
|
21
|
+
//# sourceMappingURL=self-hosted-scheduler-interval.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-hosted-scheduler-interval.d.ts","sourceRoot":"","sources":["../src/self-hosted-scheduler-interval.ts"],"names":[],"mappings":"AAqBA;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAmBvF;AAED;;;;;;;;;GASG;AACH,wBAAgB,kCAAkC,CAChD,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,SAAS,CAcpB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/**
|
|
3
|
+
* #1140 — the self-hosted scheduler interval has two places it can be set:
|
|
4
|
+
* `cms-provision init --scheduler-interval-minutes` records it in
|
|
5
|
+
* `.caelo/config.json` (which every CLI render — `up`, `upgrade`, agent
|
|
6
|
+
* apply — reads), and the Pulumi stack has the config key
|
|
7
|
+
* `caelo-self-hosted:schedulerIntervalMinutes`. Both rewrite the same
|
|
8
|
+
* `docker-compose.yml`, so if each read only its own source a `pulumi up`
|
|
9
|
+
* over a CLI install would silently put the interval back to the default,
|
|
10
|
+
* and the next CLI `upgrade` would undo a Pulumi-only value the same way.
|
|
11
|
+
*
|
|
12
|
+
* The recorded `.caelo/config.json` is the install's one record (the CLI
|
|
13
|
+
* renders from nothing else), so the stack takes the interval from it; the
|
|
14
|
+
* Pulumi key may restate it but a different value is refused rather than
|
|
15
|
+
* one side winning silently (CLAUDE.md §2: no fallbacks).
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
18
|
+
import { parseSchedulerIntervalMinutes } from "./stack-contract.js";
|
|
19
|
+
/**
|
|
20
|
+
* Read the interval `init` recorded in a `.caelo/config.json`.
|
|
21
|
+
*
|
|
22
|
+
* @param configPath - the install's `config.json`.
|
|
23
|
+
* @returns the recorded minutes, or undefined when there is no config.json
|
|
24
|
+
* (a Pulumi-only install) or it records no interval (the default).
|
|
25
|
+
* @throws when the file is not JSON or the recorded value is out of bounds.
|
|
26
|
+
*/
|
|
27
|
+
export function recordedSchedulerIntervalMinutes(configPath) {
|
|
28
|
+
if (!existsSync(configPath))
|
|
29
|
+
return undefined;
|
|
30
|
+
let parsed;
|
|
31
|
+
try {
|
|
32
|
+
parsed = JSON.parse(readFileSync(configPath, "utf8"));
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
throw new Error(`${configPath} is not valid JSON: ${e.message}`);
|
|
36
|
+
}
|
|
37
|
+
const raw = parsed !== null && typeof parsed === "object"
|
|
38
|
+
? parsed.schedulerIntervalMinutes
|
|
39
|
+
: undefined;
|
|
40
|
+
if (raw === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
if (typeof raw !== "number") {
|
|
43
|
+
throw new Error(`${configPath}: schedulerIntervalMinutes ${JSON.stringify(raw)} is not a number of minutes`);
|
|
44
|
+
}
|
|
45
|
+
return parseSchedulerIntervalMinutes(raw, `${configPath}: schedulerIntervalMinutes`);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The interval the self-hosted Pulumi stack renders into the Compose file.
|
|
49
|
+
*
|
|
50
|
+
* @param pulumiValue - `caelo-self-hosted:schedulerIntervalMinutes`, if set.
|
|
51
|
+
* @param recorded - what {@link recordedSchedulerIntervalMinutes} read.
|
|
52
|
+
* @param configPath - named in the refusal.
|
|
53
|
+
* @returns the minutes to render; undefined means neither source sets one
|
|
54
|
+
* (the generator's default).
|
|
55
|
+
* @throws when both are set and differ.
|
|
56
|
+
*/
|
|
57
|
+
export function selfHostedSchedulerIntervalMinutes(pulumiValue, recorded, configPath) {
|
|
58
|
+
if (pulumiValue === undefined)
|
|
59
|
+
return recorded;
|
|
60
|
+
const minutes = parseSchedulerIntervalMinutes(pulumiValue, "caelo-self-hosted:schedulerIntervalMinutes");
|
|
61
|
+
if (recorded !== undefined && recorded !== minutes) {
|
|
62
|
+
throw new Error(`caelo-self-hosted:schedulerIntervalMinutes is ${minutes} but ${configPath} records ${recorded}; ` +
|
|
63
|
+
"the CLI renders the Compose file from config.json, so the two must agree. " +
|
|
64
|
+
`Set the Pulumi key to ${recorded}, or remove it (\`pulumi config rm caelo-self-hosted:schedulerIntervalMinutes\`) to use the recorded value.`);
|
|
65
|
+
}
|
|
66
|
+
return minutes;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=self-hosted-scheduler-interval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-hosted-scheduler-interval.js","sourceRoot":"","sources":["../src/self-hosted-scheduler-interval.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AAEpE;;;;;;;GAOG;AACH,MAAM,UAAU,gCAAgC,CAAC,UAAkB;IACjE,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,uBAAwB,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,GAAG,GACP,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;QAC3C,CAAC,CAAE,MAAiD,CAAC,wBAAwB;QAC7E,CAAC,CAAC,SAAS,CAAC;IAChB,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,8BAA8B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,6BAA6B,CAC5F,CAAC;IACJ,CAAC;IACD,OAAO,6BAA6B,CAAC,GAAG,EAAE,GAAG,UAAU,4BAA4B,CAAC,CAAC;AACvF,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kCAAkC,CAChD,WAA+B,EAC/B,QAA4B,EAC5B,UAAkB;IAElB,IAAI,WAAW,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAC/C,MAAM,OAAO,GAAG,6BAA6B,CAC3C,WAAW,EACX,4CAA4C,CAC7C,CAAC;IACF,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CACb,iDAAiD,OAAO,QAAQ,UAAU,YAAY,QAAQ,IAAI;YAChG,4EAA4E;YAC5E,yBAAyB,QAAQ,6GAA6G,CACjJ,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Start (or converge) a self-hosted Compose install — what `init` and `up`
|
|
3
|
-
* run after writing `.caelo/`, so one command ends with a serving install
|
|
4
|
-
* (CLAUDE.md §11.C, issue #707) instead of printing steps to copy.
|
|
5
|
-
*
|
|
6
|
-
* Order, and why:
|
|
7
|
-
* 1. pull every image, with the progress on the terminal (the admin image
|
|
8
|
-
* is large; a silent multi-minute step reads as a hang);
|
|
9
|
-
* 2. start Postgres and wait for its health check — on a fresh volume its
|
|
10
|
-
* first start runs bootstrap.sh (roles + databases);
|
|
11
|
-
* 3. apply the migrations with the install's admin image;
|
|
12
|
-
* 4. start everything (`--remove-orphans` drops services an older Compose
|
|
13
|
-
* file had, e.g. the pgBackRest sidecar);
|
|
14
|
-
* 5. health-check the admin (`/_caelo/health` proves the DB pool and its
|
|
15
|
-
* role) and the gateway;
|
|
16
|
-
* 6. reload Caddy — Compose does not restart a running Caddy when only
|
|
17
|
-
* its bind-mounted Caddyfile changed, so a re-run `up` would otherwise
|
|
18
|
-
* keep serving the old vhosts.
|
|
19
|
-
* Every step converges, so a re-run after a failure picks up where it
|
|
20
|
-
* stopped.
|
|
21
|
-
*/
|
|
22
1
|
import type { HostRunner } from "./self-hosted-release.js";
|
|
23
2
|
export interface StartDeps {
|
|
24
3
|
readonly caeloDir: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-hosted-start.d.ts","sourceRoot":"","sources":["../src/self-hosted-start.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"self-hosted-start.d.ts","sourceRoot":"","sources":["../src/self-hosted-start.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAI3D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,oEAAoE;IACpE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E,KAAK,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEjF,sGAAsG;AACtG,wBAAsB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CA+D3E;AAED,gFAAgF;AAChF,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBtD"}
|
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Start (or converge) a self-hosted Compose install — what `init` and `up`
|
|
4
|
+
* run after writing `.caelo/`, so one command ends with a serving install
|
|
5
|
+
* (CLAUDE.md §11.C, issue #707) instead of printing steps to copy.
|
|
6
|
+
*
|
|
7
|
+
* Order, and why:
|
|
8
|
+
* 1. pull every image, with the progress on the terminal (the admin image
|
|
9
|
+
* is large; a silent multi-minute step reads as a hang);
|
|
10
|
+
* 2. start Postgres and wait for its health check — on a fresh volume its
|
|
11
|
+
* first start runs bootstrap.sh (roles + databases);
|
|
12
|
+
* 3. apply the migrations with the install's admin image;
|
|
13
|
+
* 4. start everything (`--remove-orphans` drops services an older Compose
|
|
14
|
+
* file had, e.g. the pgBackRest sidecar);
|
|
15
|
+
* 5. health-check the admin (`/_caelo/health` proves the DB pool and its
|
|
16
|
+
* role), the gateway and — when the release has one — the
|
|
17
|
+
* MCP-Auth-Proxy (#1328);
|
|
18
|
+
* 6. reload Caddy — Compose does not restart a running Caddy when only
|
|
19
|
+
* its bind-mounted Caddyfile changed, so a re-run `up` would otherwise
|
|
20
|
+
* keep serving the old vhosts.
|
|
21
|
+
* Every step converges, so a re-run after a failure picks up where it
|
|
22
|
+
* stopped.
|
|
23
|
+
*/
|
|
24
|
+
import { COMPOSE_MCP_AUTH_PROXY_SERVICE } from "./compose.js";
|
|
2
25
|
import { compose, runMigrations, waitHealthy } from "./self-hosted-upgrade.js";
|
|
3
26
|
/** Bring the install's Compose stack up and prove it serves. Never throws for an expected failure. */
|
|
4
27
|
export async function startSelfHosted(deps) {
|
|
@@ -25,7 +48,22 @@ export async function startSelfHosted(deps) {
|
|
|
25
48
|
});
|
|
26
49
|
if (up.exitCode !== 0)
|
|
27
50
|
return fail("start", "docker compose up failed (see above).");
|
|
28
|
-
|
|
51
|
+
// #1328 — the MCP-Auth-Proxy too, when the release this file runs has one
|
|
52
|
+
// (a release from before it has none; Compose knows which).
|
|
53
|
+
const listed = await runner.run(compose(caeloDir, "config", "--services"));
|
|
54
|
+
if (listed.exitCode !== 0) {
|
|
55
|
+
return fail("start", `docker compose config --services failed: ${listed.stderr.trim()}`);
|
|
56
|
+
}
|
|
57
|
+
const runsProxy = listed.stdout
|
|
58
|
+
.split("\n")
|
|
59
|
+
.map((s) => s.trim())
|
|
60
|
+
.includes(COMPOSE_MCP_AUTH_PROXY_SERVICE);
|
|
61
|
+
const services = [
|
|
62
|
+
"admin",
|
|
63
|
+
"gateway",
|
|
64
|
+
...(runsProxy ? ["mcp-auth-proxy"] : []),
|
|
65
|
+
];
|
|
66
|
+
for (const service of services) {
|
|
29
67
|
log(`Waiting for the ${service} to answer its health check …`);
|
|
30
68
|
const healthy = await waitHealthy(service, caeloDir, {
|
|
31
69
|
runner,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-hosted-start.js","sourceRoot":"","sources":["../src/self-hosted-start.ts"],"names":[],"mappings":"AAAA,mCAAmC;
|
|
1
|
+
{"version":3,"file":"self-hosted-start.js","sourceRoot":"","sources":["../src/self-hosted-start.ts"],"names":[],"mappings":"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"}
|