@caelo-cms/provisioning 0.10.46 → 0.10.48

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 (342) hide show
  1. package/dist/adc-impersonation.d.ts.map +1 -1
  2. package/dist/adc-impersonation.js +23 -1
  3. package/dist/adc-impersonation.js.map +1 -1
  4. package/dist/agent/apply.d.ts +45 -0
  5. package/dist/agent/apply.d.ts.map +1 -0
  6. package/dist/agent/apply.js +83 -0
  7. package/dist/agent/apply.js.map +1 -0
  8. package/dist/agent/cli-provenance.d.ts +42 -0
  9. package/dist/agent/cli-provenance.d.ts.map +1 -0
  10. package/dist/agent/cli-provenance.js +138 -0
  11. package/dist/agent/cli-provenance.js.map +1 -0
  12. package/dist/agent/command.d.ts +79 -0
  13. package/dist/agent/command.d.ts.map +1 -0
  14. package/dist/agent/command.js +454 -0
  15. package/dist/agent/command.js.map +1 -0
  16. package/dist/agent/config.d.ts +30 -0
  17. package/dist/agent/config.d.ts.map +1 -0
  18. package/dist/agent/config.js +60 -0
  19. package/dist/agent/config.js.map +1 -0
  20. package/dist/agent/lock.d.ts +13 -0
  21. package/dist/agent/lock.d.ts.map +1 -0
  22. package/dist/agent/lock.js +100 -0
  23. package/dist/agent/lock.js.map +1 -0
  24. package/dist/agent/queue.d.ts +35 -0
  25. package/dist/agent/queue.d.ts.map +1 -0
  26. package/dist/agent/queue.js +50 -0
  27. package/dist/agent/queue.js.map +1 -0
  28. package/dist/agent/run.d.ts +97 -0
  29. package/dist/agent/run.d.ts.map +1 -0
  30. package/dist/agent/run.js +198 -0
  31. package/dist/agent/run.js.map +1 -0
  32. package/dist/agent/systemd.d.ts +55 -0
  33. package/dist/agent/systemd.d.ts.map +1 -0
  34. package/dist/agent/systemd.js +171 -0
  35. package/dist/agent/systemd.js.map +1 -0
  36. package/dist/agent/units.d.ts +44 -0
  37. package/dist/agent/units.d.ts.map +1 -0
  38. package/dist/agent/units.js +127 -0
  39. package/dist/agent/units.js.map +1 -0
  40. package/dist/agent-db.js +18362 -0
  41. package/dist/cli.js +122 -16
  42. package/dist/cli.js.map +1 -1
  43. package/dist/cloudsql-iam-user.d.ts +39 -0
  44. package/dist/cloudsql-iam-user.d.ts.map +1 -0
  45. package/dist/cloudsql-iam-user.js +119 -0
  46. package/dist/cloudsql-iam-user.js.map +1 -0
  47. package/dist/compose.d.ts +16 -0
  48. package/dist/compose.d.ts.map +1 -1
  49. package/dist/compose.js +26 -1
  50. package/dist/compose.js.map +1 -1
  51. package/dist/dns/index.d.ts +2 -0
  52. package/dist/dns/index.d.ts.map +1 -1
  53. package/dist/dns/index.js +3 -2
  54. package/dist/dns/index.js.map +1 -1
  55. package/dist/dns/manual.d.ts +5 -0
  56. package/dist/dns/manual.d.ts.map +1 -1
  57. package/dist/dns/manual.js +28 -12
  58. package/dist/dns/manual.js.map +1 -1
  59. package/dist/gcloud.d.ts +2 -0
  60. package/dist/gcloud.d.ts.map +1 -1
  61. package/dist/gcloud.js +1 -1
  62. package/dist/gcloud.js.map +1 -1
  63. package/dist/gcp-names.d.ts +15 -0
  64. package/dist/gcp-names.d.ts.map +1 -1
  65. package/dist/gcp-names.js +23 -0
  66. package/dist/gcp-names.js.map +1 -1
  67. package/dist/index.d.ts +6 -0
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +4 -0
  70. package/dist/index.js.map +1 -1
  71. package/dist/infra-contract.d.ts +1 -1
  72. package/dist/infra-contract.js +7 -1
  73. package/dist/infra-contract.js.map +1 -1
  74. package/dist/install-job-runner.d.ts +13 -0
  75. package/dist/install-job-runner.d.ts.map +1 -0
  76. package/dist/install-job-runner.js +155 -0
  77. package/dist/install-job-runner.js.map +1 -0
  78. package/dist/install-job.d.ts +210 -0
  79. package/dist/install-job.d.ts.map +1 -0
  80. package/dist/install-job.js +449 -0
  81. package/dist/install-job.js.map +1 -0
  82. package/dist/install-state.d.ts +19 -1
  83. package/dist/install-state.d.ts.map +1 -1
  84. package/dist/install-state.js +31 -3
  85. package/dist/install-state.js.map +1 -1
  86. package/dist/lifecycle.d.ts.map +1 -1
  87. package/dist/lifecycle.js +24 -5
  88. package/dist/lifecycle.js.map +1 -1
  89. package/dist/migration-runner.d.ts +5 -0
  90. package/dist/migration-runner.d.ts.map +1 -1
  91. package/dist/migration-runner.js +1 -1
  92. package/dist/migration-runner.js.map +1 -1
  93. package/dist/operator-access.d.ts +14 -8
  94. package/dist/operator-access.d.ts.map +1 -1
  95. package/dist/operator-access.js +16 -102
  96. package/dist/operator-access.js.map +1 -1
  97. package/dist/run-mode.d.ts +27 -0
  98. package/dist/run-mode.d.ts.map +1 -0
  99. package/dist/run-mode.js +22 -0
  100. package/dist/run-mode.js.map +1 -0
  101. package/dist/runtime-secrets.d.ts +19 -0
  102. package/dist/runtime-secrets.d.ts.map +1 -1
  103. package/dist/runtime-secrets.js +44 -0
  104. package/dist/runtime-secrets.js.map +1 -1
  105. package/dist/self-hosted-roles.d.ts +22 -1
  106. package/dist/self-hosted-roles.d.ts.map +1 -1
  107. package/dist/self-hosted-roles.js +81 -12
  108. package/dist/self-hosted-roles.js.map +1 -1
  109. package/dist/self-hosted-upgrade.d.ts +17 -0
  110. package/dist/self-hosted-upgrade.d.ts.map +1 -1
  111. package/dist/self-hosted-upgrade.js +16 -1
  112. package/dist/self-hosted-upgrade.js.map +1 -1
  113. package/dist/stack-contract.d.ts +6 -0
  114. package/dist/stack-contract.d.ts.map +1 -1
  115. package/dist/stack-contract.js +10 -1
  116. package/dist/stack-contract.js.map +1 -1
  117. package/dist/state-attach.d.ts +23 -0
  118. package/dist/state-attach.d.ts.map +1 -0
  119. package/dist/state-attach.js +112 -0
  120. package/dist/state-attach.js.map +1 -0
  121. package/dist/state-backend.d.ts +11 -0
  122. package/dist/state-backend.d.ts.map +1 -1
  123. package/dist/state-backend.js +20 -0
  124. package/dist/state-backend.js.map +1 -1
  125. package/dist/state-command.d.ts +20 -0
  126. package/dist/state-command.d.ts.map +1 -0
  127. package/dist/state-command.js +237 -0
  128. package/dist/state-command.js.map +1 -0
  129. package/dist/state-migrate.d.ts +121 -0
  130. package/dist/state-migrate.d.ts.map +1 -0
  131. package/dist/state-migrate.js +290 -0
  132. package/dist/state-migrate.js.map +1 -0
  133. package/dist/state-pulumi.d.ts +17 -0
  134. package/dist/state-pulumi.d.ts.map +1 -0
  135. package/dist/state-pulumi.js +218 -0
  136. package/dist/state-pulumi.js.map +1 -0
  137. package/dist/state-store.d.ts +27 -0
  138. package/dist/state-store.d.ts.map +1 -1
  139. package/dist/state-store.js +65 -0
  140. package/dist/state-store.js.map +1 -1
  141. package/dist/upgrade/converge.d.ts +6 -0
  142. package/dist/upgrade/converge.d.ts.map +1 -1
  143. package/dist/upgrade/converge.js +59 -2
  144. package/dist/upgrade/converge.js.map +1 -1
  145. package/dist/upgrade/gcp-lookup.d.ts +6 -0
  146. package/dist/upgrade/gcp-lookup.d.ts.map +1 -1
  147. package/dist/upgrade/gcp-lookup.js +25 -0
  148. package/dist/upgrade/gcp-lookup.js.map +1 -1
  149. package/dist/upgrade/release-images.d.ts +12 -0
  150. package/dist/upgrade/release-images.d.ts.map +1 -1
  151. package/dist/upgrade/release-images.js +31 -0
  152. package/dist/upgrade/release-images.js.map +1 -1
  153. package/dist/upgrade/upgrade.d.ts +5 -0
  154. package/dist/upgrade/upgrade.d.ts.map +1 -1
  155. package/dist/upgrade/upgrade.js +28 -1
  156. package/dist/upgrade/upgrade.js.map +1 -1
  157. package/dist/upgrader-assess.d.ts +82 -0
  158. package/dist/upgrader-assess.d.ts.map +1 -0
  159. package/dist/upgrader-assess.js +116 -0
  160. package/dist/upgrader-assess.js.map +1 -0
  161. package/dist/upgrader-gcp.d.ts +17 -0
  162. package/dist/upgrader-gcp.d.ts.map +1 -0
  163. package/dist/upgrader-gcp.js +87 -0
  164. package/dist/upgrader-gcp.js.map +1 -0
  165. package/dist/upgrader-job.d.ts +131 -0
  166. package/dist/upgrader-job.d.ts.map +1 -0
  167. package/dist/upgrader-job.js +259 -0
  168. package/dist/upgrader-job.js.map +1 -0
  169. package/dist/upgrader-reporter.d.ts +35 -0
  170. package/dist/upgrader-reporter.d.ts.map +1 -0
  171. package/dist/upgrader-reporter.js +79 -0
  172. package/dist/upgrader-reporter.js.map +1 -0
  173. package/dist/upgrader-setup.d.ts +59 -0
  174. package/dist/upgrader-setup.d.ts.map +1 -0
  175. package/dist/upgrader-setup.js +308 -0
  176. package/dist/upgrader-setup.js.map +1 -0
  177. package/dist/wizard.d.ts +6 -0
  178. package/dist/wizard.d.ts.map +1 -1
  179. package/dist/wizard.js +32 -4
  180. package/dist/wizard.js.map +1 -1
  181. package/dist/wizards/gcp-firebase.d.ts +3 -0
  182. package/dist/wizards/gcp-firebase.d.ts.map +1 -1
  183. package/dist/wizards/gcp-firebase.js +1 -0
  184. package/dist/wizards/gcp-firebase.js.map +1 -1
  185. package/dist/wizards/gcp-install-job.d.ts +74 -0
  186. package/dist/wizards/gcp-install-job.d.ts.map +1 -0
  187. package/dist/wizards/gcp-install-job.js +398 -0
  188. package/dist/wizards/gcp-install-job.js.map +1 -0
  189. package/dist/wizards/gcp-prompts.d.ts +3 -0
  190. package/dist/wizards/gcp-prompts.d.ts.map +1 -0
  191. package/dist/wizards/gcp-prompts.js +25 -0
  192. package/dist/wizards/gcp-prompts.js.map +1 -0
  193. package/dist/wizards/gcp-pulumi.d.ts +9 -2
  194. package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
  195. package/dist/wizards/gcp-pulumi.js +8 -6
  196. package/dist/wizards/gcp-pulumi.js.map +1 -1
  197. package/dist/wizards/gcp.d.ts +40 -0
  198. package/dist/wizards/gcp.d.ts.map +1 -1
  199. package/dist/wizards/gcp.js +291 -83
  200. package/dist/wizards/gcp.js.map +1 -1
  201. package/package.json +6 -4
  202. package/src/adapter.ts +97 -0
  203. package/src/adc-impersonation.ts +176 -0
  204. package/src/admin-domain.test.ts +254 -0
  205. package/src/admin-domain.ts +245 -0
  206. package/src/admin-memory.test.ts +151 -0
  207. package/src/agent/apply.test.ts +185 -0
  208. package/src/agent/apply.ts +124 -0
  209. package/src/agent/cli-provenance.test.ts +159 -0
  210. package/src/agent/cli-provenance.ts +191 -0
  211. package/src/agent/command.test.ts +77 -0
  212. package/src/agent/command.ts +564 -0
  213. package/src/agent/config.ts +86 -0
  214. package/src/agent/lock-config.test.ts +97 -0
  215. package/src/agent/lock.ts +110 -0
  216. package/src/agent/queue.test.ts +10 -0
  217. package/src/agent/queue.ts +91 -0
  218. package/src/agent/run.test.ts +382 -0
  219. package/src/agent/run.ts +295 -0
  220. package/src/agent/systemd.ts +209 -0
  221. package/src/agent/units.test.ts +223 -0
  222. package/src/agent/units.ts +163 -0
  223. package/src/azure-front-door.test.ts +119 -0
  224. package/src/azure-front-door.ts +56 -0
  225. package/src/bootstrap-token.ts +20 -0
  226. package/src/caddy.ts +112 -0
  227. package/src/cdn-copy.ts +91 -0
  228. package/src/cert-wait.test.ts +194 -0
  229. package/src/cert-wait.ts +163 -0
  230. package/src/checkpoint-secrets.test.ts +380 -0
  231. package/src/checkpoint-secrets.ts +283 -0
  232. package/src/cli-routing.test.ts +45 -0
  233. package/src/cli-routing.ts +43 -0
  234. package/src/cli.ts +1491 -0
  235. package/src/cloudsql-iam-user.ts +147 -0
  236. package/src/compose.ts +334 -0
  237. package/src/default-firewall.test.ts +411 -0
  238. package/src/default-firewall.ts +342 -0
  239. package/src/deployed-release.test.ts +231 -0
  240. package/src/deployed-release.ts +220 -0
  241. package/src/dns/cloudflare.ts +182 -0
  242. package/src/dns/groups.test.ts +76 -0
  243. package/src/dns/groups.ts +86 -0
  244. package/src/dns/index.ts +56 -0
  245. package/src/dns/manual.ts +130 -0
  246. package/src/dns/types.ts +27 -0
  247. package/src/gateway-credentials.test.ts +180 -0
  248. package/src/gateway-credentials.ts +144 -0
  249. package/src/gcloud-components.test.ts +76 -0
  250. package/src/gcloud-components.ts +85 -0
  251. package/src/gcloud-retry.ts +41 -0
  252. package/src/gcloud-runner.test.ts +61 -0
  253. package/src/gcloud.test.ts +99 -0
  254. package/src/gcloud.ts +322 -0
  255. package/src/gcp-names.ts +135 -0
  256. package/src/index.test.ts +332 -0
  257. package/src/index.ts +114 -0
  258. package/src/infra-contract.ts +32 -0
  259. package/src/install-job-runner.ts +166 -0
  260. package/src/install-job.test.ts +566 -0
  261. package/src/install-job.ts +542 -0
  262. package/src/install-state.test.ts +239 -0
  263. package/src/install-state.ts +583 -0
  264. package/src/internal-token.ts +35 -0
  265. package/src/lifecycle.ts +900 -0
  266. package/src/mcp-iap-stacks.test.ts +58 -0
  267. package/src/mcp-iap.test.ts +149 -0
  268. package/src/mcp-iap.ts +131 -0
  269. package/src/media-volume.test.ts +296 -0
  270. package/src/migration-runner.ts +365 -0
  271. package/src/operator-access-stacks.test.ts +55 -0
  272. package/src/operator-access.test.ts +332 -0
  273. package/src/operator-access.ts +554 -0
  274. package/src/ops-backend.test.ts +320 -0
  275. package/src/ops-backend.ts +414 -0
  276. package/src/provisioner-identity.test.ts +482 -0
  277. package/src/provisioner-identity.ts +407 -0
  278. package/src/redirects-emit.ts +175 -0
  279. package/src/region-data.ts +428 -0
  280. package/src/regions.test.ts +277 -0
  281. package/src/regions.ts +370 -0
  282. package/src/release-contract.ts +57 -0
  283. package/src/release-manifest.test.ts +293 -0
  284. package/src/release-manifest.ts +430 -0
  285. package/src/run-mode.ts +40 -0
  286. package/src/runtime-secrets.test.ts +627 -0
  287. package/src/runtime-secrets.ts +754 -0
  288. package/src/self-command.test.ts +14 -0
  289. package/src/self-command.ts +21 -0
  290. package/src/self-hosted-compose.test.ts +177 -0
  291. package/src/self-hosted-release.ts +240 -0
  292. package/src/self-hosted-roles.integration.test.ts +161 -0
  293. package/src/self-hosted-roles.test.ts +124 -0
  294. package/src/self-hosted-roles.ts +203 -0
  295. package/src/self-hosted-upgrade.test.ts +394 -0
  296. package/src/self-hosted-upgrade.ts +548 -0
  297. package/src/stack-contract-parity.test.ts +199 -0
  298. package/src/stack-contract.test.ts +391 -0
  299. package/src/stack-contract.ts +888 -0
  300. package/src/stack-converge-secrets.test.ts +421 -0
  301. package/src/stack-converge.test.ts +833 -0
  302. package/src/stack-converge.ts +909 -0
  303. package/src/staging-admin.test.ts +246 -0
  304. package/src/staging-admin.ts +324 -0
  305. package/src/state-attach.test.ts +211 -0
  306. package/src/state-attach.ts +132 -0
  307. package/src/state-backend.test.ts +145 -0
  308. package/src/state-backend.ts +262 -0
  309. package/src/state-command.ts +293 -0
  310. package/src/state-migrate.test.ts +479 -0
  311. package/src/state-migrate.ts +434 -0
  312. package/src/state-pulumi.ts +289 -0
  313. package/src/state-store.test.ts +212 -0
  314. package/src/state-store.ts +243 -0
  315. package/src/upgrade/app-roll.ts +486 -0
  316. package/src/upgrade/backup.ts +109 -0
  317. package/src/upgrade/converge.ts +437 -0
  318. package/src/upgrade/gcp-lookup.ts +167 -0
  319. package/src/upgrade/health.test.ts +279 -0
  320. package/src/upgrade/health.ts +305 -0
  321. package/src/upgrade/release-images.test.ts +119 -0
  322. package/src/upgrade/release-images.ts +391 -0
  323. package/src/upgrade/reporter.ts +46 -0
  324. package/src/upgrade/upgrade.test.ts +626 -0
  325. package/src/upgrade/upgrade.ts +249 -0
  326. package/src/upgrader-assess.test.ts +265 -0
  327. package/src/upgrader-assess.ts +233 -0
  328. package/src/upgrader-gcp.ts +123 -0
  329. package/src/upgrader-job.test.ts +408 -0
  330. package/src/upgrader-job.ts +499 -0
  331. package/src/upgrader-reporter.test.ts +46 -0
  332. package/src/upgrader-reporter.ts +105 -0
  333. package/src/upgrader-setup.test.ts +169 -0
  334. package/src/upgrader-setup.ts +355 -0
  335. package/src/wizard.ts +425 -0
  336. package/src/wizards/gcp-cost.ts +188 -0
  337. package/src/wizards/gcp-firebase.ts +72 -0
  338. package/src/wizards/gcp-install-job.ts +506 -0
  339. package/src/wizards/gcp-prompts.ts +26 -0
  340. package/src/wizards/gcp-pulumi.test.ts +246 -0
  341. package/src/wizards/gcp-pulumi.ts +516 -0
  342. package/src/wizards/gcp.ts +1935 -0
@@ -0,0 +1,100 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * One upgrade at a time per self-hosted install (#696 Phase 4c): the host
4
+ * agent and a hand-run `cms-provision upgrade` both take
5
+ * `.caelo/upgrade.lock` for the whole run — two concurrent rolls would
6
+ * overwrite each other's Compose file and restore the wrong one on rollback.
7
+ *
8
+ * The file holds the holder's pid; a lock whose process is gone (a crash, a
9
+ * reboot) is taken over rather than blocking updates forever.
10
+ *
11
+ * The record is written to a private temp file first and then hard-linked
12
+ * into place, so the lock file never exists half-written: a reader that
13
+ * finds it can always trust its pid. (An unreadable file is only taken over
14
+ * once it is older than any run could be.)
15
+ */
16
+ import { linkSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ /** `.caelo/upgrade.lock`. */
19
+ export function upgradeLockPath(caeloDir) {
20
+ return join(caeloDir, "upgrade.lock");
21
+ }
22
+ /** An unreadable lock file younger than this still counts as held (longer than any run). */
23
+ const UNREADABLE_LOCK_MAX_AGE_MS = 2 * 60 * 60 * 1000;
24
+ /** The lock file's modification time (0 when it vanished meanwhile). */
25
+ function lockMtime(path) {
26
+ try {
27
+ return statSync(path).mtimeMs;
28
+ }
29
+ catch {
30
+ return 0;
31
+ }
32
+ }
33
+ /** Whether process `pid` exists (signal 0 checks without signalling). */
34
+ function processAlive(pid) {
35
+ try {
36
+ process.kill(pid, 0);
37
+ return true;
38
+ }
39
+ catch (e) {
40
+ // EPERM: it exists, it is just someone else's.
41
+ return e.code === "EPERM";
42
+ }
43
+ }
44
+ /**
45
+ * Take the install's upgrade lock for `holder`.
46
+ *
47
+ * @returns the release function (idempotent)
48
+ * @throws when a live process holds it, naming that holder
49
+ */
50
+ export function acquireUpgradeLock(caeloDir, holder, deps = {}) {
51
+ const path = upgradeLockPath(caeloDir);
52
+ const alive = deps.alive ?? processAlive;
53
+ const record = {
54
+ pid: deps.pid ?? process.pid,
55
+ holder,
56
+ at: new Date().toISOString(),
57
+ };
58
+ const temp = `${path}.${record.pid}.${crypto.randomUUID()}`;
59
+ writeFileSync(temp, JSON.stringify(record), { mode: 0o600, flag: "wx" });
60
+ try {
61
+ for (let attempt = 0; attempt < 2; attempt++) {
62
+ try {
63
+ // Atomic: fails with EEXIST when someone holds the lock.
64
+ linkSync(temp, path);
65
+ let released = false;
66
+ return () => {
67
+ if (released)
68
+ return;
69
+ released = true;
70
+ rmSync(path, { force: true });
71
+ };
72
+ }
73
+ catch (e) {
74
+ if (e.code !== "EEXIST")
75
+ throw e;
76
+ }
77
+ let held = null;
78
+ try {
79
+ held = JSON.parse(readFileSync(path, "utf8"));
80
+ }
81
+ catch {
82
+ // Corrupt (never half-written, see above): take it over only when old.
83
+ }
84
+ if (held === null) {
85
+ if (Date.now() - lockMtime(path) < UNREADABLE_LOCK_MAX_AGE_MS) {
86
+ throw new Error(`another upgrade holds ${path} (its record is unreadable).`);
87
+ }
88
+ }
89
+ else if (typeof held.pid === "number" && alive(held.pid)) {
90
+ throw new Error(`${held.holder ?? "another upgrade"} is running on this install (pid ${held.pid}, since ${held.at ?? "?"}).`);
91
+ }
92
+ rmSync(path, { force: true });
93
+ }
94
+ }
95
+ finally {
96
+ rmSync(temp, { force: true });
97
+ }
98
+ throw new Error(`could not take ${path}; another process keeps creating it.`);
99
+ }
100
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/agent/lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { UpdateQueue } from "../upgrader-job.js";
2
+ /** One check-in of the agent (`platform_update_agent`). */
3
+ export interface AgentHeartbeat {
4
+ /** The Caelo release of the agent's own code. */
5
+ readonly agentVersion: string;
6
+ /** The host it runs on. */
7
+ readonly host: string;
8
+ /** Why an install would fail on this host right now; null when none. */
9
+ readonly problem: string | null;
10
+ }
11
+ /** The upgrader's queue plus the agent's heartbeat. */
12
+ export interface AgentQueue extends UpdateQueue {
13
+ heartbeat(beat: AgentHeartbeat): Promise<void>;
14
+ }
15
+ /** Where the agent's database login reaches Postgres (loopback only). */
16
+ export interface AgentDbConnection {
17
+ readonly user: string;
18
+ readonly password: string;
19
+ readonly port: number;
20
+ }
21
+ /** An open queue and the pools behind it. */
22
+ export interface OpenedAgentQueue {
23
+ readonly queue: AgentQueue;
24
+ close(): Promise<void>;
25
+ }
26
+ /** Opens the queue over the agent's login (`@caelo-cms/platform-updater` agent-db). */
27
+ export type OpenAgentQueue = (conn: AgentDbConnection) => Promise<OpenedAgentQueue>;
28
+ /**
29
+ * Load the function that opens the agent's queue: the bundle shipped in the
30
+ * published package, else (a source checkout) the workspace package.
31
+ *
32
+ * @throws when neither is present — a build that skipped the bundle
33
+ */
34
+ export declare function loadAgentQueueOpener(): Promise<OpenAgentQueue>;
35
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/agent/queue.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,uDAAuD;AACvD,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,SAAS,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,yEAAyE;AACzE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,uFAAuF;AACvF,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAiBpF;;;;;GAKG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,cAAc,CAAC,CAmBpE"}
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * The self-hosted host agent's database side (#696 Phase 4c): the same
4
+ * {@link UpdateQueue} the Google Cloud upgrader job drives, plus the
5
+ * heartbeat the admin reads to decide whether to offer "Install update".
6
+ *
7
+ * The queue is implemented in `@caelo-cms/platform-updater` (the job ops,
8
+ * through the Query API — never raw SQL), which the published CLI cannot
9
+ * depend on: it is private, and it depends on this package. So the build
10
+ * bundles its `agent-db` entry into `dist/agent-db.js` (package.json
11
+ * `build`), and {@link loadAgentQueueOpener} imports that file; a source
12
+ * checkout imports the workspace package instead.
13
+ */
14
+ import { existsSync } from "node:fs";
15
+ import { fileURLToPath } from "node:url";
16
+ /**
17
+ * Where the bundle is, relative to this module: next to the compiled CLI
18
+ * (`dist/agent/queue.js` → `dist/agent-db.js`), or — when Bun loads the
19
+ * published package's `src/` through its `bun` export condition — in the
20
+ * package's `dist/`.
21
+ */
22
+ const BUNDLED_AGENT_DB = ["../agent-db.js", "../../dist/agent-db.js"];
23
+ /**
24
+ * The workspace package a source checkout loads instead. Held in a variable
25
+ * so TypeScript does not resolve it: provisioning cannot declare a
26
+ * dependency on the package that depends on it.
27
+ */
28
+ const WORKSPACE_AGENT_DB = "@caelo-cms/platform-updater/agent-db";
29
+ /**
30
+ * Load the function that opens the agent's queue: the bundle shipped in the
31
+ * published package, else (a source checkout) the workspace package.
32
+ *
33
+ * @throws when neither is present — a build that skipped the bundle
34
+ */
35
+ export async function loadAgentQueueOpener() {
36
+ const bundled = BUNDLED_AGENT_DB.map((rel) => new URL(rel, import.meta.url)).find((url) => existsSync(fileURLToPath(url)));
37
+ const specifier = bundled?.href ?? WORKSPACE_AGENT_DB;
38
+ let mod;
39
+ try {
40
+ mod = (await import(specifier));
41
+ }
42
+ catch (e) {
43
+ throw new Error(`the update agent's database module is missing (${specifier}: ${e instanceof Error ? e.message : String(e)}). This @caelo-cms/provisioning build is incomplete — reinstall it.`);
44
+ }
45
+ if (typeof mod.openAgentQueue !== "function") {
46
+ throw new Error(`${specifier} does not export openAgentQueue — reinstall @caelo-cms/provisioning.`);
47
+ }
48
+ return mod.openAgentQueue;
49
+ }
50
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/agent/queue.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAkCzC;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,CAAC,gBAAgB,EAAE,wBAAwB,CAAU,CAAC;AAE/E;;;;GAIG;AACH,MAAM,kBAAkB,GAAG,sCAAsC,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CACxF,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAC/B,CAAC;IACF,MAAM,SAAS,GAAG,OAAO,EAAE,IAAI,IAAI,kBAAkB,CAAC;IACtD,IAAI,GAAwC,CAAC;IAC7C,IAAI,CAAC;QACH,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAAwC,CAAC;IACzE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,kDAAkD,SAAS,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,qEAAqE,CAChL,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,cAAc,KAAK,UAAU,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CACb,GAAG,SAAS,sEAAsE,CACnF,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC,cAAc,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * One poll of the self-hosted host agent (#696 Phase 4c) — what the
3
+ * `caelo-agent-<domain>-<hash>` timer runs every minute:
4
+ *
5
+ * 1. preflight (Docker reachable, cosign present, a recorded release) and
6
+ * a heartbeat with the result, so Settings → Updates knows the agent is
7
+ * alive and what would stop an install before the Owner clicks;
8
+ * 2. claim the oldest pending request (ending a run that died mid-way) —
9
+ * the admin only ever writes the request row;
10
+ * 3. verify the target's signed release manifest (cosign, fixed registry
11
+ * and signer — nothing from the request but the version) and decide
12
+ * with the upgrader's own refusal matrix (upgrader-assess.ts): bad
13
+ * signature, downgrade, below minFromVersion, contract migrations or a
14
+ * policy refusal on an automatic run. Self-hosted has no separately
15
+ * converged infrastructure, so the infra-contract row never applies;
16
+ * 4. install the TARGET release's own CLI from npm and verify its registry
17
+ * signatures + provenance (agent/cli-provenance.ts, the checks of the
18
+ * Cloud Shell runner) — refused outright when they fail;
19
+ * 5. only then run that CLI's `agent apply` (agent/apply.ts), which
20
+ * performs the same backup → pull → migrate → roll → health → rollback
21
+ * as a hand-run `upgrade` and narrates it into the request's timeline.
22
+ * The target's CLI renders the target's Compose file, so a release that
23
+ * changes the stack needs no extra step. No code of the target runs
24
+ * before its manifest verified and passed the checks above;
25
+ * 6. if that process ended without recording an end state, end the
26
+ * request as failed with its output.
27
+ *
28
+ * The install's upgrade lock is held for the whole run, so a hand-run
29
+ * `upgrade` and the agent never roll at the same time.
30
+ */
31
+ import { type PlatformUpdateTrigger } from "@caelo-cms/shared";
32
+ import type { ReleaseManifestResult } from "../release-manifest.js";
33
+ import type { SelfHostedRelease } from "../self-hosted-release.js";
34
+ import type { UpdateEndStatus } from "../upgrader-job.js";
35
+ import { type JobLog } from "../upgrader-reporter.js";
36
+ import type { VerifiedCli } from "./cli-provenance.js";
37
+ import type { AgentQueue } from "./queue.js";
38
+ /** What the target release's `agent apply` is told (argv of the child). */
39
+ export interface AgentApplyRequest {
40
+ readonly requestId: string;
41
+ readonly targetVersion: string;
42
+ readonly trigger: PlatformUpdateTrigger;
43
+ /** From the verified manifest: the images the target must resolve to. */
44
+ readonly digests: {
45
+ readonly admin: string;
46
+ readonly gateway: string;
47
+ };
48
+ /** The target's CLI, installed and provenance-verified (agent/cli-provenance.ts). */
49
+ readonly cliPath: string;
50
+ }
51
+ /** How the target's `agent apply` process ended. */
52
+ export interface AgentApplyOutcome {
53
+ readonly exitCode: number;
54
+ /** The tail of its output, for the timeline when it recorded nothing. */
55
+ readonly output: string;
56
+ }
57
+ export interface AgentRunDeps {
58
+ readonly queue: AgentQueue;
59
+ /** This agent's own release (CAELO_VERSION). */
60
+ readonly agentVersion: string;
61
+ readonly host: string;
62
+ /** Why an install would fail on this host now, or null. */
63
+ readonly preflight: () => Promise<string | null>;
64
+ /** `.caelo/release.json` (null when none is recorded; throws when malformed). */
65
+ readonly readInstalled: () => SelfHostedRelease | null;
66
+ /** fetchVerifiedReleaseManifest against the fixed registry. */
67
+ readonly fetchManifest: (version: string) => Promise<ReleaseManifestResult>;
68
+ /** Take the install's upgrade lock (agent/lock.ts); throws when held. */
69
+ readonly lock: () => () => void;
70
+ /**
71
+ * Install the target release's CLI and verify its npm signatures +
72
+ * provenance (agent/cli-provenance.ts). Nothing of it runs unless this
73
+ * passes.
74
+ */
75
+ readonly verifyTargetCli: (version: string) => Promise<VerifiedCli>;
76
+ /** Run the target release's `agent apply` and wait for it. */
77
+ readonly applyTarget: (request: AgentApplyRequest) => Promise<AgentApplyOutcome>;
78
+ readonly now: () => Date;
79
+ readonly log: JobLog;
80
+ readonly sleep?: (ms: number) => Promise<void>;
81
+ /**
82
+ * How often the agent keeps checking in while the target's CLI runs (an
83
+ * update takes minutes; the admin would otherwise think the agent gone).
84
+ * Default: every poll interval.
85
+ */
86
+ readonly heartbeatEveryMs?: number;
87
+ }
88
+ /** What one poll did. */
89
+ export interface AgentRunResult {
90
+ readonly exitCode: number;
91
+ readonly requestId: string | null;
92
+ /** The end the agent itself recorded (null when the target's CLI did, or nothing ran). */
93
+ readonly status: UpdateEndStatus | null;
94
+ }
95
+ /** One poll. Never throws; see the file comment for the sequence. */
96
+ export declare function runAgentOnce(deps: AgentRunDeps): Promise<AgentRunResult>;
97
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/agent/run.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAsC,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACnG,OAAO,KAAK,EAAmB,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,KAAK,EAAa,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErE,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,2EAA2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC;IACxC,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,gDAAgD;IAChD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACjD,iFAAiF;IACjF,QAAQ,CAAC,aAAa,EAAE,MAAM,iBAAiB,GAAG,IAAI,CAAC;IACvD,+DAA+D;IAC/D,QAAQ,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC5E,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,MAAM,IAAI,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IACpE,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACjF,QAAQ,CAAC,GAAG,EAAE,MAAM,IAAI,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,yBAAyB;AACzB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;CACzC;AAED,qEAAqE;AACrE,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAmL9E"}
@@ -0,0 +1,198 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * One poll of the self-hosted host agent (#696 Phase 4c) — what the
4
+ * `caelo-agent-<domain>-<hash>` timer runs every minute:
5
+ *
6
+ * 1. preflight (Docker reachable, cosign present, a recorded release) and
7
+ * a heartbeat with the result, so Settings → Updates knows the agent is
8
+ * alive and what would stop an install before the Owner clicks;
9
+ * 2. claim the oldest pending request (ending a run that died mid-way) —
10
+ * the admin only ever writes the request row;
11
+ * 3. verify the target's signed release manifest (cosign, fixed registry
12
+ * and signer — nothing from the request but the version) and decide
13
+ * with the upgrader's own refusal matrix (upgrader-assess.ts): bad
14
+ * signature, downgrade, below minFromVersion, contract migrations or a
15
+ * policy refusal on an automatic run. Self-hosted has no separately
16
+ * converged infrastructure, so the infra-contract row never applies;
17
+ * 4. install the TARGET release's own CLI from npm and verify its registry
18
+ * signatures + provenance (agent/cli-provenance.ts, the checks of the
19
+ * Cloud Shell runner) — refused outright when they fail;
20
+ * 5. only then run that CLI's `agent apply` (agent/apply.ts), which
21
+ * performs the same backup → pull → migrate → roll → health → rollback
22
+ * as a hand-run `upgrade` and narrates it into the request's timeline.
23
+ * The target's CLI renders the target's Compose file, so a release that
24
+ * changes the stack needs no extra step. No code of the target runs
25
+ * before its manifest verified and passed the checks above;
26
+ * 6. if that process ended without recording an end state, end the
27
+ * request as failed with its output.
28
+ *
29
+ * The install's upgrade lock is held for the whole run, so a hand-run
30
+ * `upgrade` and the agent never roll at the same time.
31
+ */
32
+ import { PLATFORM_UPDATE_AGENT_POLL_SECONDS } from "@caelo-cms/shared";
33
+ import { assessUpgradeRequest } from "../upgrader-assess.js";
34
+ import { recordUpdateEnd } from "../upgrader-job.js";
35
+ import { eventReporter } from "../upgrader-reporter.js";
36
+ /** One poll. Never throws; see the file comment for the sequence. */
37
+ export async function runAgentOnce(deps) {
38
+ const { queue, log } = deps;
39
+ const problem = await deps.preflight().catch((e) => `preflight failed: ${errorText(e)}`);
40
+ try {
41
+ await queue.heartbeat({ agentVersion: deps.agentVersion, host: deps.host, problem });
42
+ }
43
+ catch (e) {
44
+ log({ severity: "ERROR", message: `could not check in with the database: ${errorText(e)}` });
45
+ return { exitCode: 1, requestId: null, status: null };
46
+ }
47
+ let claimed;
48
+ try {
49
+ claimed = await queue.claim(`agent@${deps.host}`.slice(0, 200));
50
+ }
51
+ catch (e) {
52
+ log({ severity: "ERROR", message: `could not read update requests: ${errorText(e)}` });
53
+ return { exitCode: 1, requestId: null, status: null };
54
+ }
55
+ if (!claimed)
56
+ return { exitCode: 0, requestId: null, status: null };
57
+ const request = claimed;
58
+ const r = eventReporter((phase, level, message) => queue.event(request.id, phase, level, message), log, request.id);
59
+ let release = null;
60
+ const unlock = () => {
61
+ try {
62
+ release?.();
63
+ }
64
+ catch (e) {
65
+ log({ severity: "WARNING", message: `could not release the upgrade lock: ${errorText(e)}` });
66
+ }
67
+ release = null;
68
+ };
69
+ const stopWith = async (status, codes, reason) => {
70
+ r.phase("finish");
71
+ r.error(reason);
72
+ await r.flush();
73
+ unlock();
74
+ const end = {
75
+ status,
76
+ reason,
77
+ codes,
78
+ pauseAutoUpdates: request.trigger === "auto" && (status === "failed" || status === "rolled_back"),
79
+ };
80
+ const recorded = await recordUpdateEnd(queue, request.id, end, log, deps.sleep);
81
+ const failed = status === "failed" || !recorded;
82
+ return { exitCode: failed ? 1 : 0, requestId: request.id, status };
83
+ };
84
+ try {
85
+ r.phase("start");
86
+ r.info(`The update agent on ${deps.host} (Caelo ${deps.agentVersion}) picked up the request to install Caelo ${request.targetVersion}.`);
87
+ if (problem) {
88
+ return await stopWith("failed", ["preflight"], `Nothing was changed: ${problem} Fix this on the server, then try again.`);
89
+ }
90
+ try {
91
+ release = deps.lock();
92
+ }
93
+ catch (e) {
94
+ return await stopWith("failed", ["state-locked"], `Nothing was changed: ${errorText(e)} Try again when it has finished.`);
95
+ }
96
+ r.phase("verify");
97
+ let installed;
98
+ try {
99
+ installed = deps.readInstalled();
100
+ }
101
+ catch (e) {
102
+ return await stopWith("failed", ["install-state"], `Nothing was changed: ${errorText(e)}`);
103
+ }
104
+ const manifest = await deps.fetchManifest(request.targetVersion);
105
+ const decision = assessUpgradeRequest({
106
+ request,
107
+ manifest,
108
+ installed: { version: installed?.version ?? null, infraContractVersion: null },
109
+ policy: request.policy,
110
+ now: deps.now(),
111
+ manualPath: "server",
112
+ });
113
+ if (decision.manifest) {
114
+ r.success(`Release information of ${decision.manifest.version} verified: signed by Caelo's release workflow.`);
115
+ await recordFacts(queue, request.id, decision.manifest);
116
+ }
117
+ r.phase("assess");
118
+ if (decision.kind === "stop") {
119
+ return await stopWith(decision.status, decision.codes, decision.reason);
120
+ }
121
+ for (const w of decision.warnings)
122
+ r.warn(w);
123
+ const m = decision.manifest;
124
+ const step = r.step(`Fetching the Caelo ${m.version} installer and verifying its npm provenance...`);
125
+ const cli = await deps.verifyTargetCli(m.version);
126
+ if (!cli.ok) {
127
+ step.failed(cli.error.message);
128
+ // A package that is not the release's is refused; a missing npm or a
129
+ // failed download is a failure to retry.
130
+ const refused = ["audit-signatures", "version", "provenance"].includes(cli.error.code);
131
+ return await stopWith(refused ? "refused" : "failed", [`cli-${cli.error.code}`], `Nothing was changed: the installer of Caelo ${m.version} ${refused ? "is not the one Caelo's release workflow published" : "could not be fetched"} (${cli.error.message}).`);
132
+ }
133
+ step.done(`The Caelo ${m.version} installer is signed and was built by Caelo's release workflow.`);
134
+ r.info(`${installed?.version} → ${m.version}: handing over to the Caelo ${m.version} installer on this server.`);
135
+ await r.flush();
136
+ const beat = setInterval(() => {
137
+ queue
138
+ .heartbeat({ agentVersion: deps.agentVersion, host: deps.host, problem: null })
139
+ .catch((e) => {
140
+ log({ severity: "WARNING", message: `could not check in: ${errorText(e)}` });
141
+ });
142
+ }, deps.heartbeatEveryMs ?? PLATFORM_UPDATE_AGENT_POLL_SECONDS * 1000);
143
+ let outcome;
144
+ try {
145
+ outcome = await deps.applyTarget({
146
+ requestId: request.id,
147
+ targetVersion: m.version,
148
+ trigger: request.trigger,
149
+ digests: { admin: m.digests.admin, gateway: m.digests.gateway },
150
+ cliPath: cli.cliPath,
151
+ });
152
+ }
153
+ finally {
154
+ clearInterval(beat);
155
+ }
156
+ unlock();
157
+ if (outcome.exitCode === 0)
158
+ return { exitCode: 0, requestId: request.id, status: null };
159
+ // The target's CLI ends the request itself; only if it could not (it
160
+ // never started, or crashed) is the request still running here.
161
+ const reason = `The Caelo ${m.version} installer stopped (exit ${outcome.exitCode}) before it recorded how the update ended. If the site misbehaves, check \`docker compose ps\` on the server.${outcome.output ? `\n${outcome.output}` : ""}`;
162
+ const end = {
163
+ status: "failed",
164
+ reason: reason.slice(0, 4000),
165
+ codes: ["apply"],
166
+ pauseAutoUpdates: request.trigger === "auto",
167
+ };
168
+ let ended = false;
169
+ try {
170
+ ended = await queue.finish(request.id, end);
171
+ }
172
+ catch (e) {
173
+ log({ severity: "ERROR", message: `could not end request ${request.id}: ${errorText(e)}` });
174
+ return { exitCode: 1, requestId: request.id, status: null };
175
+ }
176
+ if (!ended)
177
+ return { exitCode: 1, requestId: request.id, status: null };
178
+ r.phase("finish");
179
+ r.error(reason);
180
+ await r.flush();
181
+ return { exitCode: 1, requestId: request.id, status: "failed" };
182
+ }
183
+ catch (e) {
184
+ return await stopWith("failed", ["internal"], `The update agent stopped unexpectedly: ${errorText(e)}. If the site misbehaves, check \`docker compose ps\` on the server.`);
185
+ }
186
+ }
187
+ async function recordFacts(queue, requestId, m) {
188
+ await queue.record(requestId, {
189
+ manifestSecurity: m.security,
190
+ contractMigrations: m.migrations.contract,
191
+ adminDigest: m.digests.admin,
192
+ gatewayDigest: m.digests.gateway,
193
+ });
194
+ }
195
+ function errorText(e) {
196
+ return e instanceof Error ? e.message : String(e);
197
+ }
198
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/agent/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { HostRunner } from "../self-hosted-release.js";
2
+ import { type AgentUnitSpec } from "./units.js";
3
+ /** The host the units go to. */
4
+ export interface AgentHost {
5
+ readonly runner: HostRunner;
6
+ /** `~/.config/systemd/user` (or `$XDG_CONFIG_HOME/systemd/user`). */
7
+ readonly unitDir: string;
8
+ /** The operator's login name (for lingering). */
9
+ readonly user: string;
10
+ readonly platform: NodeJS.Platform;
11
+ }
12
+ /** The real host: this user's systemd user-unit directory. */
13
+ export declare function currentAgentHost(runner: HostRunner): AgentHost;
14
+ /**
15
+ * Why the agent cannot be installed on this host, or null. Linux with a
16
+ * systemd user manager is the supported target; macOS (Docker Desktop) is
17
+ * a development setup, and there `upgrade` is run by hand.
18
+ */
19
+ export declare function agentHostProblem(host: AgentHost): Promise<string | null>;
20
+ /** `<unitDir>/<name>.service` + `.timer`. */
21
+ export declare function agentUnitPaths(host: Pick<AgentHost, "unitDir">, name: string): {
22
+ service: string;
23
+ timer: string;
24
+ };
25
+ export type AgentUnitsResult = {
26
+ readonly ok: true;
27
+ readonly warnings: readonly string[];
28
+ } | {
29
+ readonly ok: false;
30
+ readonly error: string;
31
+ };
32
+ /**
33
+ * Write both units, reload, enable + start the timer, and make sure the
34
+ * user lingers. Idempotent: re-running rewrites the same files.
35
+ */
36
+ export declare function installAgentUnits(spec: AgentUnitSpec, host: AgentHost): Promise<AgentUnitsResult>;
37
+ /** The release the installed service runs, or null when it is not installed. */
38
+ export declare function installedAgentVersion(host: AgentHost, name: string): string | null;
39
+ /**
40
+ * Re-pin an installed agent to `spec.version` (after an update). Does
41
+ * nothing when the agent is not installed.
42
+ */
43
+ export declare function repinAgentUnits(spec: AgentUnitSpec, host: AgentHost): Promise<AgentUnitsResult & {
44
+ readonly installed?: boolean;
45
+ }>;
46
+ /** Stop + disable the timer and delete both units. */
47
+ export declare function uninstallAgentUnits(host: AgentHost, name: string): Promise<AgentUnitsResult>;
48
+ /** `systemctl --user status` of both units (text for the terminal). */
49
+ export declare function agentUnitStatus(host: AgentHost, name: string): Promise<string>;
50
+ /** The argv that shows the agent's log (journald). */
51
+ export declare function agentLogsArgv(name: string, opts: {
52
+ lines: number;
53
+ follow: boolean;
54
+ }): string[];
55
+ //# sourceMappingURL=systemd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"systemd.d.ts","sourceRoot":"","sources":["../../src/agent/systemd.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EACL,KAAK,aAAa,EAInB,MAAM,YAAY,CAAC;AAEpB,gCAAgC;AAChC,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;CACpC;AAED,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAQ9D;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS9E;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM;;;EAK5E;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AASnD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,gBAAgB,CAAC,CAiB3B;AAYD,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQlF;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,gBAAgB,GAAG;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAoB9D;AAED,sDAAsD;AACtD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,CAAC,CAU3B;AAED,uEAAuE;AACvE,wBAAsB,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWpF;AAED,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,EAAE,CAW9F"}