@caelo-cms/provisioning 0.10.44 → 0.10.47

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.
Files changed (146) hide show
  1. package/dist/adc-impersonation.d.ts +28 -0
  2. package/dist/adc-impersonation.d.ts.map +1 -0
  3. package/dist/adc-impersonation.js +148 -0
  4. package/dist/adc-impersonation.js.map +1 -0
  5. package/dist/checkpoint-secrets.d.ts.map +1 -1
  6. package/dist/checkpoint-secrets.js +2 -1
  7. package/dist/checkpoint-secrets.js.map +1 -1
  8. package/dist/cli.js +202 -33
  9. package/dist/cli.js.map +1 -1
  10. package/dist/compose.d.ts +45 -0
  11. package/dist/compose.d.ts.map +1 -1
  12. package/dist/compose.js +112 -29
  13. package/dist/compose.js.map +1 -1
  14. package/dist/gcloud-retry.d.ts +5 -1
  15. package/dist/gcloud-retry.d.ts.map +1 -1
  16. package/dist/gcloud-retry.js.map +1 -1
  17. package/dist/gcloud.d.ts +2 -1
  18. package/dist/gcloud.d.ts.map +1 -1
  19. package/dist/gcloud.js +11 -13
  20. package/dist/gcloud.js.map +1 -1
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +3 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/infra-contract.d.ts +24 -0
  26. package/dist/infra-contract.d.ts.map +1 -0
  27. package/dist/infra-contract.js +25 -0
  28. package/dist/infra-contract.js.map +1 -0
  29. package/dist/install-state.d.ts +66 -2
  30. package/dist/install-state.d.ts.map +1 -1
  31. package/dist/install-state.js +162 -22
  32. package/dist/install-state.js.map +1 -1
  33. package/dist/lifecycle.d.ts +6 -0
  34. package/dist/lifecycle.d.ts.map +1 -1
  35. package/dist/lifecycle.js +189 -819
  36. package/dist/lifecycle.js.map +1 -1
  37. package/dist/migration-runner.d.ts +3 -0
  38. package/dist/migration-runner.d.ts.map +1 -1
  39. package/dist/migration-runner.js +7 -5
  40. package/dist/migration-runner.js.map +1 -1
  41. package/dist/ops-backend.d.ts +46 -0
  42. package/dist/ops-backend.d.ts.map +1 -0
  43. package/dist/ops-backend.js +370 -0
  44. package/dist/ops-backend.js.map +1 -0
  45. package/dist/provisioner-identity.d.ts +103 -0
  46. package/dist/provisioner-identity.d.ts.map +1 -0
  47. package/dist/provisioner-identity.js +323 -0
  48. package/dist/provisioner-identity.js.map +1 -0
  49. package/dist/regions.d.ts.map +1 -1
  50. package/dist/regions.js +2 -1
  51. package/dist/regions.js.map +1 -1
  52. package/dist/release-contract.d.ts +37 -0
  53. package/dist/release-contract.d.ts.map +1 -0
  54. package/dist/release-contract.js +55 -0
  55. package/dist/release-contract.js.map +1 -0
  56. package/dist/release-manifest.d.ts +140 -0
  57. package/dist/release-manifest.d.ts.map +1 -0
  58. package/dist/release-manifest.js +319 -0
  59. package/dist/release-manifest.js.map +1 -0
  60. package/dist/self-command.d.ts +16 -0
  61. package/dist/self-command.d.ts.map +1 -0
  62. package/dist/self-command.js +20 -0
  63. package/dist/self-command.js.map +1 -0
  64. package/dist/self-hosted-release.d.ts +81 -0
  65. package/dist/self-hosted-release.d.ts.map +1 -0
  66. package/dist/self-hosted-release.js +148 -0
  67. package/dist/self-hosted-release.js.map +1 -0
  68. package/dist/self-hosted-upgrade.d.ts +91 -0
  69. package/dist/self-hosted-upgrade.d.ts.map +1 -0
  70. package/dist/self-hosted-upgrade.js +355 -0
  71. package/dist/self-hosted-upgrade.js.map +1 -0
  72. package/dist/stack-converge.d.ts.map +1 -1
  73. package/dist/stack-converge.js +2 -1
  74. package/dist/stack-converge.js.map +1 -1
  75. package/dist/state-attach.d.ts +23 -0
  76. package/dist/state-attach.d.ts.map +1 -0
  77. package/dist/state-attach.js +112 -0
  78. package/dist/state-attach.js.map +1 -0
  79. package/dist/state-backend.d.ts +114 -0
  80. package/dist/state-backend.d.ts.map +1 -0
  81. package/dist/state-backend.js +200 -0
  82. package/dist/state-backend.js.map +1 -0
  83. package/dist/state-command.d.ts +20 -0
  84. package/dist/state-command.d.ts.map +1 -0
  85. package/dist/state-command.js +237 -0
  86. package/dist/state-command.js.map +1 -0
  87. package/dist/state-migrate.d.ts +121 -0
  88. package/dist/state-migrate.d.ts.map +1 -0
  89. package/dist/state-migrate.js +290 -0
  90. package/dist/state-migrate.js.map +1 -0
  91. package/dist/state-pulumi.d.ts +17 -0
  92. package/dist/state-pulumi.d.ts.map +1 -0
  93. package/dist/state-pulumi.js +218 -0
  94. package/dist/state-pulumi.js.map +1 -0
  95. package/dist/state-store.d.ts +82 -0
  96. package/dist/state-store.d.ts.map +1 -0
  97. package/dist/state-store.js +205 -0
  98. package/dist/state-store.js.map +1 -0
  99. package/dist/upgrade/app-roll.d.ts +164 -0
  100. package/dist/upgrade/app-roll.d.ts.map +1 -0
  101. package/dist/upgrade/app-roll.js +270 -0
  102. package/dist/upgrade/app-roll.js.map +1 -0
  103. package/dist/upgrade/backup.d.ts +48 -0
  104. package/dist/upgrade/backup.d.ts.map +1 -0
  105. package/dist/upgrade/backup.js +71 -0
  106. package/dist/upgrade/backup.js.map +1 -0
  107. package/dist/upgrade/converge.d.ts +45 -0
  108. package/dist/upgrade/converge.d.ts.map +1 -0
  109. package/dist/upgrade/converge.js +287 -0
  110. package/dist/upgrade/converge.js.map +1 -0
  111. package/dist/upgrade/gcp-lookup.d.ts +23 -0
  112. package/dist/upgrade/gcp-lookup.d.ts.map +1 -0
  113. package/dist/upgrade/gcp-lookup.js +95 -0
  114. package/dist/upgrade/gcp-lookup.js.map +1 -0
  115. package/dist/upgrade/health.d.ts +99 -0
  116. package/dist/upgrade/health.d.ts.map +1 -0
  117. package/dist/upgrade/health.js +214 -0
  118. package/dist/upgrade/health.js.map +1 -0
  119. package/dist/upgrade/release-images.d.ts +125 -0
  120. package/dist/upgrade/release-images.d.ts.map +1 -0
  121. package/dist/upgrade/release-images.js +315 -0
  122. package/dist/upgrade/release-images.js.map +1 -0
  123. package/dist/upgrade/reporter.d.ts +17 -0
  124. package/dist/upgrade/reporter.d.ts.map +1 -0
  125. package/dist/upgrade/reporter.js +28 -0
  126. package/dist/upgrade/reporter.js.map +1 -0
  127. package/dist/upgrade/upgrade.d.ts +79 -0
  128. package/dist/upgrade/upgrade.d.ts.map +1 -0
  129. package/dist/upgrade/upgrade.js +105 -0
  130. package/dist/upgrade/upgrade.js.map +1 -0
  131. package/dist/wizard.d.ts.map +1 -1
  132. package/dist/wizard.js +7 -3
  133. package/dist/wizard.js.map +1 -1
  134. package/dist/wizards/gcp-cost.d.ts.map +1 -1
  135. package/dist/wizards/gcp-cost.js +7 -1
  136. package/dist/wizards/gcp-cost.js.map +1 -1
  137. package/dist/wizards/gcp-pulumi.d.ts +104 -8
  138. package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
  139. package/dist/wizards/gcp-pulumi.js +159 -50
  140. package/dist/wizards/gcp-pulumi.js.map +1 -1
  141. package/dist/wizards/gcp.d.ts.map +1 -1
  142. package/dist/wizards/gcp.js +246 -78
  143. package/dist/wizards/gcp.js.map +1 -1
  144. package/package.json +4 -3
  145. package/stacks/self-hosted/README.md +4 -0
  146. package/stacks/self-hosted/index.ts +10 -2
@@ -0,0 +1,315 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * Caelo release images — where they live, how a tag becomes a digest, and
4
+ * which signer identity cosign must see. The ONE module for this, shared by
5
+ * every install path that runs the prebuilt images (CLAUDE.md §11.C):
6
+ * - the GCP `upgrade` (Artifact Registry mirror, {@link RELEASE_REGISTRY});
7
+ * - the self-hosted Compose install + upgrade (GHCR, the canonical
8
+ * registry, {@link ghcrRepository}).
9
+ * Both registries carry the SAME digests: release-images.yml pushes to GHCR,
10
+ * signs, then `oras copy -r`s image + signature to the mirror. So one
11
+ * resolver and one cosign identity serve both. The in-cloud upgrader job
12
+ * (epic #696) takes the digests from the signed release manifest instead.
13
+ */
14
+ import { confirm, isCancel, log, spinner } from "@clack/prompts";
15
+ import { green, red } from "kleur/colors";
16
+ /** The services every install runs, in roll order (admin first, then gateway). */
17
+ export const RELEASE_SERVICES = ["admin", "gateway"];
18
+ /** GHCR — the canonical registry (release-images.yml), used by self-hosted Compose. */
19
+ export const GHCR_REGISTRY = "ghcr.io";
20
+ export const GHCR_NAMESPACE = "caelo-cms";
21
+ /** `ghcr.io/caelo-cms/<service>` — the repository of a service's release image. */
22
+ export function ghcrRepository(service) {
23
+ return `${GHCR_REGISTRY}/${GHCR_NAMESPACE}/${service}`;
24
+ }
25
+ /** Where Caelo's release workflows live; every signer identity starts here. */
26
+ export const RELEASE_WORKFLOWS_URL = "https://github.com/caelo-cms/caelo-cms/.github/workflows";
27
+ /**
28
+ * The keyless signer cosign must see on every release image: one of the two
29
+ * release workflows of the caelo-cms repo, via GitHub's OIDC issuer. A
30
+ * different identity means a registry compromise, a typosquat, or a fork's
31
+ * image — every caller refuses to run it.
32
+ */
33
+ export const RELEASE_SIGNER_IDENTITY_REGEXP = `${RELEASE_WORKFLOWS_URL}/(release-images|release).yml@.*`;
34
+ /** OIDC issuer of every Caelo release signature — images and release manifest (GitHub Actions). */
35
+ export const RELEASE_OIDC_ISSUER = "https://token.actions.githubusercontent.com";
36
+ /**
37
+ * The `cosign verify` argv for one image reference pinned by digest.
38
+ *
39
+ * @example cosignVerifyArgv("ghcr.io/caelo-cms/admin@sha256:…")
40
+ */
41
+ export function cosignVerifyArgv(imageRef) {
42
+ return [
43
+ "cosign",
44
+ "verify",
45
+ imageRef,
46
+ "--certificate-identity-regexp",
47
+ RELEASE_SIGNER_IDENTITY_REGEXP,
48
+ "--certificate-oidc-issuer",
49
+ RELEASE_OIDC_ISSUER,
50
+ ];
51
+ }
52
+ /** A `sha256:<64 hex>` image / blob digest. */
53
+ export const IMAGE_DIGEST = /^sha256:[0-9a-f]{64}$/;
54
+ /** Whether `s` is a well-formed `sha256:<64 hex>` digest. */
55
+ export function isImageDigest(s) {
56
+ return IMAGE_DIGEST.test(s);
57
+ }
58
+ const HEX_DIGITS = "0123456789abcdef";
59
+ /**
60
+ * `s` rebuilt character by character from a constant alphabet when it is a
61
+ * well-formed digest, else null. The digest comes from a registry's HTTP
62
+ * header and ends up in files (release.json, the Compose file); rebuilding
63
+ * it — rather than passing the checked string on — guarantees that nothing
64
+ * but `sha256:` and 64 hex digits from our own constants is ever written.
65
+ */
66
+ export function canonicalDigest(s) {
67
+ if (!isImageDigest(s))
68
+ return null;
69
+ const hex = [...s.slice("sha256:".length)].map((c) => HEX_DIGITS[HEX_DIGITS.indexOf(c)]);
70
+ return `sha256:${hex.join("")}`;
71
+ }
72
+ const TAG_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-v";
73
+ const RELEASE_TAG = /^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
74
+ /**
75
+ * A semver release tag (`v0.10.43`, `0.11.0-rc.1`) rebuilt from a constant
76
+ * alphabet, else null. The tag comes from the GitHub API and is recorded in
77
+ * release.json, so — like {@link canonicalDigest} — only our own characters
78
+ * reach the file.
79
+ */
80
+ export function canonicalReleaseTag(s) {
81
+ if (s.length > 64 || !RELEASE_TAG.test(s))
82
+ return null;
83
+ return [...s].map((c) => TAG_CHARS[TAG_CHARS.indexOf(c)]).join("");
84
+ }
85
+ /**
86
+ * The registry tag for an upgrade request: an explicit version (a leading
87
+ * `v` dropped, as release tags are `vX.Y.Z` but image tags `X.Y.Z`), else
88
+ * the channel's moving tag, else `latest`.
89
+ */
90
+ export function releaseTag(opts) {
91
+ if (opts.version)
92
+ return opts.version.startsWith("v") ? opts.version.slice(1) : opts.version;
93
+ if (opts.channel === "rc")
94
+ return "rc";
95
+ if (opts.channel === "beta")
96
+ return "beta";
97
+ return "latest";
98
+ }
99
+ /** Manifest media types: single-arch manifests and multi-arch indexes, Docker + OCI. */
100
+ const MANIFEST_ACCEPT = [
101
+ "application/vnd.docker.distribution.manifest.v2+json",
102
+ "application/vnd.oci.image.manifest.v1+json",
103
+ "application/vnd.docker.distribution.manifest.list.v2+json",
104
+ "application/vnd.oci.image.index.v1+json",
105
+ ].join(",");
106
+ /**
107
+ * Resolve `<registryHost>/<repository>:<tag>` to the digest a `docker pull`
108
+ * of that tag would fetch, through the Docker Registry V2 API anonymously.
109
+ *
110
+ * The images are public, but registries differ in how they say so: Artifact
111
+ * Registry answers the manifest HEAD directly, GHCR answers 401 with a
112
+ * `WWW-Authenticate: Bearer realm=…,service=…,scope=…` challenge whose realm
113
+ * hands out an anonymous pull token. Both paths are handled here, so callers
114
+ * never need registry credentials (end users have none for Caelo's).
115
+ *
116
+ * @param repository - path below the host, e.g. `caelo-cms/admin`.
117
+ */
118
+ export async function resolveRegistryDigest(registryHost, repository, tag, fetchImpl = fetch) {
119
+ const url = `https://${registryHost}/v2/${repository}/manifests/${tag}`;
120
+ try {
121
+ let res = await fetchImpl(url, { method: "HEAD", headers: { Accept: MANIFEST_ACCEPT } });
122
+ if (res.status === 401) {
123
+ const token = await anonymousPullToken(res.headers.get("www-authenticate"), fetchImpl);
124
+ if (!token.ok)
125
+ return token;
126
+ res = await fetchImpl(url, {
127
+ method: "HEAD",
128
+ headers: { Accept: MANIFEST_ACCEPT, Authorization: `Bearer ${token.token}` },
129
+ });
130
+ }
131
+ if (!res.ok)
132
+ return { ok: false, reason: `HTTP ${res.status} ${res.statusText}` };
133
+ const header = res.headers.get("docker-content-digest");
134
+ const digest = header ? canonicalDigest(header) : null;
135
+ if (!digest) {
136
+ return { ok: false, reason: `unexpected digest header: ${header ?? "(missing)"}` };
137
+ }
138
+ return { ok: true, digest };
139
+ }
140
+ catch (e) {
141
+ return { ok: false, reason: e instanceof Error ? e.message : String(e) };
142
+ }
143
+ }
144
+ /** Follow a registry's Bearer challenge to an anonymous pull token. */
145
+ async function anonymousPullToken(challenge, fetchImpl) {
146
+ const params = parseBearerChallenge(challenge);
147
+ if (!params?.realm) {
148
+ return {
149
+ ok: false,
150
+ reason: `registry demanded auth without a Bearer challenge (${challenge})`,
151
+ };
152
+ }
153
+ const tokenUrl = new URL(params.realm);
154
+ if (params.service)
155
+ tokenUrl.searchParams.set("service", params.service);
156
+ if (params.scope)
157
+ tokenUrl.searchParams.set("scope", params.scope);
158
+ const res = await fetchImpl(tokenUrl.toString());
159
+ if (!res.ok)
160
+ return { ok: false, reason: `token endpoint HTTP ${res.status} ${res.statusText}` };
161
+ const body = (await res.json());
162
+ const token = body.token ?? body.access_token;
163
+ return token ? { ok: true, token } : { ok: false, reason: "token endpoint returned no token" };
164
+ }
165
+ /**
166
+ * The key/value pairs of a `Bearer k="v",k2="v2"` challenge, or null when
167
+ * it is not a Bearer challenge.
168
+ *
169
+ * @example parseBearerChallenge('Bearer realm="https://ghcr.io/token",service="ghcr.io"')
170
+ * // → { realm: "https://ghcr.io/token", service: "ghcr.io" }
171
+ */
172
+ export function parseBearerChallenge(header) {
173
+ if (!header || !/^Bearer\s/i.test(header))
174
+ return null;
175
+ const out = {};
176
+ for (const m of header.slice(header.indexOf(" ") + 1).matchAll(/(\w+)="([^"]*)"/g)) {
177
+ const [, key, value] = m;
178
+ if (key && value !== undefined)
179
+ out[key] = value;
180
+ }
181
+ return out;
182
+ }
183
+ /**
184
+ * The tag of the newest stable Caelo release on GitHub (e.g. `v0.10.43`),
185
+ * or an error reason. Used to turn "upgrade to latest" into an exact
186
+ * version before anything is resolved, so the version an install records is
187
+ * a real release, never the moving `latest` tag.
188
+ */
189
+ export async function fetchLatestReleaseTag(fetchImpl = fetch) {
190
+ try {
191
+ const res = await fetchImpl("https://api.github.com/repos/caelo-cms/caelo-cms/releases/latest", { headers: { Accept: "application/vnd.github+json" } });
192
+ if (!res.ok)
193
+ return { ok: false, reason: `GitHub API HTTP ${res.status} ${res.statusText}` };
194
+ const json = (await res.json());
195
+ const tag = json.tag_name ? canonicalReleaseTag(json.tag_name) : null;
196
+ return tag
197
+ ? { ok: true, tag }
198
+ : { ok: false, reason: `GitHub returned no usable release tag (${json.tag_name})` };
199
+ }
200
+ catch (e) {
201
+ return { ok: false, reason: e instanceof Error ? e.message : String(e) };
202
+ }
203
+ }
204
+ /** Where Caelo's release images live (public Artifact Registry repo). */
205
+ export const RELEASE_REGISTRY = {
206
+ region: "europe-west1",
207
+ project: "caelo-website",
208
+ repo: "caelo-cms-images",
209
+ };
210
+ /** The digest-pinned reference of release image `slug@digest` in the Artifact Registry mirror. */
211
+ export function releaseImageRef(slug, digest) {
212
+ const r = RELEASE_REGISTRY;
213
+ return `${r.region}-docker.pkg.dev/${r.project}/${r.repo}/${slug}@${digest}`;
214
+ }
215
+ /**
216
+ * Resolve a tag (e.g. `0.2.6` or `latest`) to its digest in the public
217
+ * Artifact Registry mirror, anonymously through the Registry V2 API
218
+ * ({@link resolveRegistryDigest}) — the caller's gcloud session needs no IAM
219
+ * access to the registry's project.
220
+ */
221
+ export function resolveTagDigest(image, tag) {
222
+ const { region, project, repo } = RELEASE_REGISTRY;
223
+ return resolveRegistryDigest(`${region}-docker.pkg.dev`, `${project}/${repo}/${image}`, tag);
224
+ }
225
+ function probeBinary(argv) {
226
+ try {
227
+ const r = Bun.spawnSync(argv, { stdout: "pipe", stderr: "pipe" });
228
+ return r.exitCode === 0;
229
+ }
230
+ catch {
231
+ return false;
232
+ }
233
+ }
234
+ /**
235
+ * Ensure cosign is on PATH. If not — and the operator is on macOS with
236
+ * brew available — offer to `brew install cosign` interactively. Falls
237
+ * back to printing the platform install URL + the --skip-verify
238
+ * escape hatch when auto-install isn't possible.
239
+ *
240
+ * Returns true if cosign is callable after this function returns.
241
+ */
242
+ async function ensureCosignAvailable() {
243
+ if (probeBinary(["cosign", "version"]))
244
+ return true;
245
+ log.error(red("cosign not found on PATH — required for image-signature verification."));
246
+ // macOS auto-install offer. Only when `brew` is itself on PATH —
247
+ // otherwise the operator is on a stripped-down install where
248
+ // homebrew was never set up, and the manual instructions are more
249
+ // useful than a failing brew shell-out.
250
+ if (process.platform === "darwin" && probeBinary(["brew", "--version"])) {
251
+ const proceed = await confirm({
252
+ message: "Install cosign via brew now? (one-shot: brew install cosign)",
253
+ initialValue: true,
254
+ });
255
+ if (!isCancel(proceed) && proceed === true) {
256
+ const s = spinner();
257
+ s.start("brew install cosign");
258
+ const installResult = Bun.spawnSync(["brew", "install", "cosign"], {
259
+ stdout: "pipe",
260
+ stderr: "pipe",
261
+ });
262
+ if (installResult.exitCode === 0 && probeBinary(["cosign", "version"])) {
263
+ s.stop(green("cosign installed ✓"));
264
+ return true;
265
+ }
266
+ const stderr = new TextDecoder().decode(installResult.stderr);
267
+ s.stop(red("brew install cosign failed"));
268
+ log.error(stderr.trim().slice(0, 500));
269
+ }
270
+ }
271
+ log.warn("Install cosign:\n" +
272
+ " • brew install cosign (macOS)\n" +
273
+ " • https://docs.sigstore.dev/cosign/installation/ (other)\n" +
274
+ "Or pass --skip-verify to roll without signature checks (NOT recommended for production).");
275
+ return false;
276
+ }
277
+ /**
278
+ * P21 ship 4 — verify cosign keyless signatures on every planned
279
+ * image digest. Sigstore Fulcio + Rekor; the certificate identity
280
+ * must match the Caelo release-images workflow. A mismatch means
281
+ * either a registry compromise, a typosquat, or the operator pointed
282
+ * at a fork's image. Either way: refuse to roll.
283
+ *
284
+ * Returns true on success (or skips with a clear error and returns
285
+ * false if cosign isn't installed / verification fails).
286
+ */
287
+ export async function verifyCosignAll(plans) {
288
+ // Probe cosign. Bun.spawnSync THROWS ENOENT when the binary is
289
+ // missing (instead of returning a non-zero exit), so the probe
290
+ // needs try/catch — relying on `exitCode !== 0` would surface a
291
+ // confusing stack trace to the operator instead of the actionable
292
+ // "install cosign" hint.
293
+ if (!(await ensureCosignAvailable()))
294
+ return false;
295
+ for (const plan of plans) {
296
+ const s = spinner();
297
+ s.start(`Verifying cosign signature for ${plan.slug}@${plan.digest.slice(0, 19)}...`);
298
+ const fullRef = releaseImageRef(plan.slug, plan.digest);
299
+ const verify = Bun.spawnSync(cosignVerifyArgv(fullRef), { stdout: "pipe", stderr: "pipe" });
300
+ if (verify.exitCode !== 0) {
301
+ const stderr = new TextDecoder().decode(verify.stderr);
302
+ s.stop(red(`cosign verify FAILED for ${plan.slug}`));
303
+ log.error(red(`${plan.slug}@${plan.digest.slice(0, 19)} signature does NOT match the Caelo release workflow identity.\n` +
304
+ "Either:\n" +
305
+ " • the registry was compromised, OR\n" +
306
+ " • you're targeting a fork's image (verify your install's registry path), OR\n" +
307
+ " • cosign / sigstore had a transient outage (retry).\n" +
308
+ `cosign stderr: ${stderr.trim().slice(0, 500)}`));
309
+ return false;
310
+ }
311
+ s.stop(green(`${plan.slug} signature verified ✓`));
312
+ }
313
+ return true;
314
+ }
315
+ //# sourceMappingURL=release-images.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-images.js","sourceRoot":"","sources":["../../src/upgrade/release-images.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /** One long-running step: started once, ended exactly once. */
2
+ export interface ReportStep {
3
+ done(message: string): void;
4
+ failed(message: string): void;
5
+ /** Ended without success, but the upgrade continues. */
6
+ warned(message: string): void;
7
+ }
8
+ export interface UpgradeReporter {
9
+ step(label: string): ReportStep;
10
+ info(message: string): void;
11
+ warn(message: string): void;
12
+ error(message: string): void;
13
+ success(message: string): void;
14
+ }
15
+ /** The CLI's reporter: a clack spinner per step, colored log lines. */
16
+ export declare function clackReporter(): UpgradeReporter;
17
+ //# sourceMappingURL=reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/upgrade/reporter.ts"],"names":[],"mappings":"AAYA,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,wDAAwD;IACxD,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;IAChC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,uEAAuE;AACvE,wBAAgB,aAAa,IAAI,eAAe,CAgB/C"}
@@ -0,0 +1,28 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * How the upgrade phases (converge.ts, app-roll.ts) tell the operator what
4
+ * they do. The CLI renders it with clack spinners; the in-cloud upgrader job
5
+ * (epic #696) will write the same lines to its run log, and the tests record
6
+ * them. The phases never import a terminal UI themselves.
7
+ */
8
+ import { log, spinner } from "@clack/prompts";
9
+ import { green, red, yellow } from "kleur/colors";
10
+ /** The CLI's reporter: a clack spinner per step, colored log lines. */
11
+ export function clackReporter() {
12
+ return {
13
+ step(label) {
14
+ const s = spinner();
15
+ s.start(label);
16
+ return {
17
+ done: (m) => s.stop(green(m)),
18
+ failed: (m) => s.stop(red(m)),
19
+ warned: (m) => s.stop(yellow(m)),
20
+ };
21
+ },
22
+ info: (m) => log.info(m),
23
+ warn: (m) => log.warn(yellow(m)),
24
+ error: (m) => log.error(red(m)),
25
+ success: (m) => log.success(m),
26
+ };
27
+ }
28
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/upgrade/reporter.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;GAKG;AAEH,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAkBlD,uEAAuE;AACvE,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,IAAI,CAAC,KAAK;YACR,MAAM,CAAC,GAAG,OAAO,EAAE,CAAC;YACpB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACf,OAAO;gBACL,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC7B,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC7B,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;aACjC,CAAC;QACJ,CAAC;QACD,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QACxB,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAChC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/B,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;KAC/B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * `cms-provision upgrade` for one gcp / gcp-firebase install: converge, then
3
+ * app-roll (epic #696). The order, and why:
4
+ *
5
+ * 1. plan (read-only): release digests, both services, the env contract
6
+ * 2. verify the images' signatures
7
+ * 3. pre-upgrade Cloud SQL backup — the first change; if it fails, the
8
+ * install is exactly as it was
9
+ * 4. converge, the part before the roll (keyless provisioner, IAM, secrets,
10
+ * MCP access)
11
+ * 5. app-roll: health baseline, migrations, the converge steps that must
12
+ * follow migrations, admin + gateway rolls, deep health check, rollback
13
+ * on failure, recorded digests
14
+ * 6. converge, the part after the roll; a complete converge records the
15
+ * install's infrastructure contract version
16
+ *
17
+ * Every side effect goes through {@link GcpUpgradeDeps}, so the sequence runs
18
+ * against a fake gcloud in tests. lifecycle.ts wires the real ones.
19
+ */
20
+ import type { GcloudRunner, Sleep } from "../gcloud-retry.js";
21
+ import type { ImageDigests } from "../install-state.js";
22
+ import type { HttpFetch } from "../runtime-secrets.js";
23
+ import { type AppRollPlan, type ReleaseImage, type RollSlug } from "./app-roll.js";
24
+ import type { HealthProbe } from "./health.js";
25
+ import type { UpgradeReporter } from "./reporter.js";
26
+ export interface GcpUpgradeTarget {
27
+ readonly provider: "gcp" | "gcp-firebase";
28
+ readonly projectId: string;
29
+ readonly region: string;
30
+ /** Pulumi stack name (`production`). */
31
+ readonly env: string;
32
+ readonly domain: string;
33
+ readonly stagingHost: string;
34
+ readonly ownerEmail: string;
35
+ /** The tag rolled to: a version (`0.11.0`) or a channel tag (`latest`, `rc`). */
36
+ readonly targetTag: string;
37
+ /** The infrastructure contract version this CLI converges to (infra-contract.ts). */
38
+ readonly infraContractVersion: number;
39
+ readonly skipVerify: boolean;
40
+ readonly skipHealthCheck: boolean;
41
+ }
42
+ export interface GcpUpgradeDeps {
43
+ readonly run: GcloudRunner;
44
+ readonly reporter: UpgradeReporter;
45
+ readonly sleep?: Sleep;
46
+ /** Cloud SQL Admin API calls (database role passwords). */
47
+ readonly http?: HttpFetch;
48
+ readonly resolveImages: (tag: string) => Promise<{
49
+ readonly ok: true;
50
+ readonly images: Record<RollSlug, ReleaseImage>;
51
+ } | {
52
+ readonly ok: false;
53
+ readonly error: string;
54
+ }>;
55
+ readonly verifyImages: (images: readonly {
56
+ slug: string;
57
+ digest: string;
58
+ }[]) => Promise<boolean>;
59
+ readonly migrate: (imageRef: string) => Promise<{
60
+ readonly ok: boolean;
61
+ readonly error?: string;
62
+ }>;
63
+ readonly healthProbe: (plan: AppRollPlan) => Promise<{
64
+ readonly ok: true;
65
+ readonly probe: HealthProbe;
66
+ } | {
67
+ readonly ok: false;
68
+ readonly error: string;
69
+ }>;
70
+ readonly recordDigests: (digests: ImageDigests) => Promise<void>;
71
+ readonly recordInfraContractVersion: (version: number) => void;
72
+ /** The operator-identity converge step (keyless provisioner); see ConvergeDeps. */
73
+ readonly provisionerIdentity?: () => Promise<boolean>;
74
+ /** Today, for the backup's description. */
75
+ readonly now?: () => Date;
76
+ }
77
+ /** Upgrade one install; true on success. See the file comment for the order. */
78
+ export declare function upgradeGcpInstall(target: GcpUpgradeTarget, deps: GcpUpgradeDeps): Promise<boolean>;
79
+ //# sourceMappingURL=upgrade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/upgrade/upgrade.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ import { executeAppRoll, planAppRoll, reportPlan, } from "./app-roll.js";
3
+ import { backupFailureHelp, restoreCommand, takeSqlBackup } from "./backup.js";
4
+ import { startConverge } from "./converge.js";
5
+ /** Upgrade one install; true on success. See the file comment for the order. */
6
+ export async function upgradeGcpInstall(target, deps) {
7
+ const { reporter: r, run } = deps;
8
+ const { projectId } = target;
9
+ // 1. Plan. Nothing changes until every lookup succeeded.
10
+ const sPre = r.step("Pre-flight: resolving services + image digests + current revisions...");
11
+ const images = await deps.resolveImages(target.targetTag);
12
+ if (!images.ok) {
13
+ sPre.failed("Couldn't resolve the release images");
14
+ r.error(images.error);
15
+ return false;
16
+ }
17
+ const planned = await planAppRoll({
18
+ provider: target.provider,
19
+ projectId,
20
+ region: target.region,
21
+ env: target.env,
22
+ domain: target.domain,
23
+ stagingHost: target.stagingHost,
24
+ }, images.images, run);
25
+ if (!planned.ok) {
26
+ sPre.failed("Pre-flight failed");
27
+ r.error(planned.error);
28
+ return false;
29
+ }
30
+ const plan = planned.plan;
31
+ sPre.done(`Pre-flight ok — ${plan.services.length} services planned`);
32
+ reportPlan(plan, r);
33
+ // 2. P21 ship 4 — signatures against the Caelo release workflow's
34
+ // identity: refuses a compromised registry, a typosquat or a fork's image.
35
+ if (!target.skipVerify) {
36
+ if (!(await deps.verifyImages(plan.services)))
37
+ return false;
38
+ }
39
+ else {
40
+ r.warn("--skip-verify set — image signatures NOT verified.");
41
+ }
42
+ // 3. The first change: a failure leaves the install exactly as it was.
43
+ const sBak = r.step("Taking a pre-upgrade Cloud SQL backup...");
44
+ const backup = await takeSqlBackup(run, { projectId, env: target.env }, `pre-upgrade to ${target.targetTag}`, deps.now);
45
+ if (!backup.ok) {
46
+ sBak.failed(`Pre-upgrade backup failed: ${backup.error}`);
47
+ r.warn(backupFailureHelp({ projectId }));
48
+ return false;
49
+ }
50
+ sBak.done(`Pre-upgrade backup ${backup.backup.backupId} of ${backup.backup.instance} taken`);
51
+ // 4. Converge, the part before the roll.
52
+ const converge = startConverge(plan, target.ownerEmail, {
53
+ run,
54
+ reporter: r,
55
+ ...(deps.sleep ? { sleep: deps.sleep } : {}),
56
+ ...(deps.http ? { http: deps.http } : {}),
57
+ ...(deps.provisionerIdentity ? { provisionerIdentity: deps.provisionerIdentity } : {}),
58
+ });
59
+ if (!(await converge.beforeAppRoll()))
60
+ return false;
61
+ // 5. App-roll, with the converge steps that sit between its own.
62
+ let health = null;
63
+ if (!target.skipHealthCheck) {
64
+ const probe = await deps.healthProbe(plan);
65
+ if (!probe.ok) {
66
+ r.error(probe.error);
67
+ r.warn("No migrations ran and no traffic moved.");
68
+ return false;
69
+ }
70
+ health = probe.probe;
71
+ }
72
+ const rolled = await executeAppRoll({
73
+ plan,
74
+ backup: backup.backup,
75
+ targetVersion: /^\d+\.\d+\.\d+/.test(target.targetTag) ? target.targetTag : null,
76
+ // Unknown until the signed release manifest names it (epic #696).
77
+ migrationsContract: null,
78
+ }, converge.hooks, {
79
+ run,
80
+ reporter: r,
81
+ ...(deps.sleep ? { sleep: deps.sleep } : {}),
82
+ migrate: deps.migrate,
83
+ health,
84
+ recordDigests: deps.recordDigests,
85
+ });
86
+ if (!rolled.ok)
87
+ return false;
88
+ r.success(`Upgrade to ${target.targetTag} complete (admin + gateway revisions serving).`);
89
+ r.info(`Pre-upgrade backup: ${backup.backup.backupId} (restore: ${restoreCommand(backup.backup)})`);
90
+ // 6. Converge, the part after the roll.
91
+ await converge.afterAppRoll();
92
+ if (converge.complete()) {
93
+ try {
94
+ deps.recordInfraContractVersion(target.infraContractVersion);
95
+ }
96
+ catch (e) {
97
+ r.warn(`Could not record the infrastructure contract version (${e instanceof Error ? e.message : String(e)}); the next upgrade converges again.`);
98
+ }
99
+ }
100
+ else {
101
+ r.warn("Some converge steps did not succeed (see above); the install is not marked as converged, so in-product updates stay unavailable until a re-run of upgrade completes them.");
102
+ }
103
+ return true;
104
+ }
105
+ //# sourceMappingURL=upgrade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/upgrade/upgrade.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAuBA,OAAO,EAQL,OAAO,EAER,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAKL,KAAK,QAAQ,EAKd,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,SAAS,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0HvE;AAyLD,OAAO,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAuBA,OAAO,EAQL,OAAO,EAER,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAML,KAAK,QAAQ,EAKd,MAAM,oBAAoB,CAAC;AAK5B,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,SAAS,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6HvE;AAyLD,OAAO,EAAE,OAAO,EAAE,CAAC"}
package/dist/wizard.js CHANGED
@@ -21,7 +21,8 @@
21
21
  import { defaultStagingHost, normalizeStagingHost, stagingHostProblem } from "@caelo-cms/shared";
22
22
  import { cancel, confirm, intro, isCancel, log, outro, select, spinner, text, } from "@clack/prompts";
23
23
  import { bold, cyan, dim, yellow } from "kleur/colors";
24
- import { deriveInstallId, ensureInstallDir, listInstalls, readMetadata, resumedMetadata, scrubInstallProgress, writeMetadata, } from "./install-state.js";
24
+ import { currentMetadata, deriveInstallId, ensureInstallDir, listInstalls, readMetadata, resumedMetadata, scrubInstallProgress, writeMetadata, } from "./install-state.js";
25
+ import { selfCommand } from "./self-command.js";
25
26
  import { runGcpWizard } from "./wizards/gcp.js";
26
27
  import { runGcpFirebaseWizard } from "./wizards/gcp-firebase.js";
27
28
  export async function runWizard(opts = {}) {
@@ -41,9 +42,12 @@ export async function runWizard(opts = {}) {
41
42
  let projectIdHint;
42
43
  let installId;
43
44
  const existing = opts.nonInteractive ? [] : listInstalls();
44
- const resumeChoice = existing.length > 0 && !opts.provider && !opts.domain && !opts.ownerEmail
45
+ const picked = existing.length > 0 && !opts.provider && !opts.domain && !opts.ownerEmail
45
46
  ? await pickInstallToResume(existing)
46
47
  : null;
48
+ // #696 — the bucket's copy for an install whose state lives there: another
49
+ // machine may have changed its domain or owner since this mirror was written.
50
+ const resumeChoice = picked ? currentMetadata(picked) : null;
47
51
  if (resumeChoice) {
48
52
  provider = resumeChoice.provider;
49
53
  domain = resumeChoice.domain;
@@ -128,7 +132,7 @@ export async function runWizard(opts = {}) {
128
132
  });
129
133
  break;
130
134
  case "self-hosted":
131
- cancel("Self-hosted wizard is the existing `cms-provision init` flow. Run `bunx @caelo-cms/provisioning init --domain ... --owner-email ...` for now; wizard polish lands in a follow-up commit.");
135
+ cancel(`Self-hosted wizard is the existing \`cms-provision init\` flow. Run \`${selfCommand("init", "--domain", "...", "--owner-email", "...")}\` for now; wizard polish lands in a follow-up commit.`);
132
136
  process.exit(0);
133
137
  break;
134
138
  case "aws":