@caelo-cms/provisioning 0.10.47 → 0.10.49

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 (321) hide show
  1. package/caddy/Caddyfile.production +1 -1
  2. package/caddy/Caddyfile.staging +1 -1
  3. package/dist/agent/apply.d.ts +45 -0
  4. package/dist/agent/apply.d.ts.map +1 -0
  5. package/dist/agent/apply.js +83 -0
  6. package/dist/agent/apply.js.map +1 -0
  7. package/dist/agent/cli-provenance.d.ts +42 -0
  8. package/dist/agent/cli-provenance.d.ts.map +1 -0
  9. package/dist/agent/cli-provenance.js +138 -0
  10. package/dist/agent/cli-provenance.js.map +1 -0
  11. package/dist/agent/command.d.ts +79 -0
  12. package/dist/agent/command.d.ts.map +1 -0
  13. package/dist/agent/command.js +454 -0
  14. package/dist/agent/command.js.map +1 -0
  15. package/dist/agent/config.d.ts +30 -0
  16. package/dist/agent/config.d.ts.map +1 -0
  17. package/dist/agent/config.js +60 -0
  18. package/dist/agent/config.js.map +1 -0
  19. package/dist/agent/lock.d.ts +13 -0
  20. package/dist/agent/lock.d.ts.map +1 -0
  21. package/dist/agent/lock.js +100 -0
  22. package/dist/agent/lock.js.map +1 -0
  23. package/dist/agent/queue.d.ts +35 -0
  24. package/dist/agent/queue.d.ts.map +1 -0
  25. package/dist/agent/queue.js +50 -0
  26. package/dist/agent/queue.js.map +1 -0
  27. package/dist/agent/run.d.ts +97 -0
  28. package/dist/agent/run.d.ts.map +1 -0
  29. package/dist/agent/run.js +198 -0
  30. package/dist/agent/run.js.map +1 -0
  31. package/dist/agent/systemd.d.ts +55 -0
  32. package/dist/agent/systemd.d.ts.map +1 -0
  33. package/dist/agent/systemd.js +171 -0
  34. package/dist/agent/systemd.js.map +1 -0
  35. package/dist/agent/units.d.ts +44 -0
  36. package/dist/agent/units.d.ts.map +1 -0
  37. package/dist/agent/units.js +127 -0
  38. package/dist/agent/units.js.map +1 -0
  39. package/dist/agent-db.js +18402 -0
  40. package/dist/cli.js +119 -16
  41. package/dist/cli.js.map +1 -1
  42. package/dist/cloudsql-iam-user.d.ts +39 -0
  43. package/dist/cloudsql-iam-user.d.ts.map +1 -0
  44. package/dist/cloudsql-iam-user.js +119 -0
  45. package/dist/cloudsql-iam-user.js.map +1 -0
  46. package/dist/compose.d.ts +16 -0
  47. package/dist/compose.d.ts.map +1 -1
  48. package/dist/compose.js +26 -1
  49. package/dist/compose.js.map +1 -1
  50. package/dist/dns/index.d.ts +2 -0
  51. package/dist/dns/index.d.ts.map +1 -1
  52. package/dist/dns/index.js +3 -2
  53. package/dist/dns/index.js.map +1 -1
  54. package/dist/dns/manual.d.ts +5 -0
  55. package/dist/dns/manual.d.ts.map +1 -1
  56. package/dist/dns/manual.js +28 -12
  57. package/dist/dns/manual.js.map +1 -1
  58. package/dist/gcloud.d.ts +2 -0
  59. package/dist/gcloud.d.ts.map +1 -1
  60. package/dist/gcloud.js +1 -1
  61. package/dist/gcloud.js.map +1 -1
  62. package/dist/gcp-names.d.ts +15 -0
  63. package/dist/gcp-names.d.ts.map +1 -1
  64. package/dist/gcp-names.js +23 -0
  65. package/dist/gcp-names.js.map +1 -1
  66. package/dist/index.d.ts +6 -0
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +4 -0
  69. package/dist/index.js.map +1 -1
  70. package/dist/infra-contract.d.ts +1 -1
  71. package/dist/infra-contract.js +7 -1
  72. package/dist/infra-contract.js.map +1 -1
  73. package/dist/install-job-runner.d.ts +13 -0
  74. package/dist/install-job-runner.d.ts.map +1 -0
  75. package/dist/install-job-runner.js +155 -0
  76. package/dist/install-job-runner.js.map +1 -0
  77. package/dist/install-job.d.ts +210 -0
  78. package/dist/install-job.d.ts.map +1 -0
  79. package/dist/install-job.js +449 -0
  80. package/dist/install-job.js.map +1 -0
  81. package/dist/install-state.d.ts +10 -1
  82. package/dist/install-state.d.ts.map +1 -1
  83. package/dist/install-state.js +10 -2
  84. package/dist/install-state.js.map +1 -1
  85. package/dist/lifecycle.d.ts.map +1 -1
  86. package/dist/lifecycle.js +19 -4
  87. package/dist/lifecycle.js.map +1 -1
  88. package/dist/migration-runner.d.ts +5 -0
  89. package/dist/migration-runner.d.ts.map +1 -1
  90. package/dist/migration-runner.js +1 -1
  91. package/dist/migration-runner.js.map +1 -1
  92. package/dist/operator-access.d.ts +14 -8
  93. package/dist/operator-access.d.ts.map +1 -1
  94. package/dist/operator-access.js +16 -102
  95. package/dist/operator-access.js.map +1 -1
  96. package/dist/release-manifest.d.ts +2 -41
  97. package/dist/release-manifest.d.ts.map +1 -1
  98. package/dist/release-manifest.js +18 -121
  99. package/dist/release-manifest.js.map +1 -1
  100. package/dist/run-mode.d.ts +27 -0
  101. package/dist/run-mode.d.ts.map +1 -0
  102. package/dist/run-mode.js +22 -0
  103. package/dist/run-mode.js.map +1 -0
  104. package/dist/runtime-secrets.d.ts +19 -0
  105. package/dist/runtime-secrets.d.ts.map +1 -1
  106. package/dist/runtime-secrets.js +44 -0
  107. package/dist/runtime-secrets.js.map +1 -1
  108. package/dist/self-hosted-roles.d.ts +22 -1
  109. package/dist/self-hosted-roles.d.ts.map +1 -1
  110. package/dist/self-hosted-roles.js +81 -12
  111. package/dist/self-hosted-roles.js.map +1 -1
  112. package/dist/self-hosted-upgrade.d.ts +17 -0
  113. package/dist/self-hosted-upgrade.d.ts.map +1 -1
  114. package/dist/self-hosted-upgrade.js +16 -1
  115. package/dist/self-hosted-upgrade.js.map +1 -1
  116. package/dist/stack-contract.d.ts +6 -0
  117. package/dist/stack-contract.d.ts.map +1 -1
  118. package/dist/stack-contract.js +10 -1
  119. package/dist/stack-contract.js.map +1 -1
  120. package/dist/upgrade/converge.d.ts +6 -0
  121. package/dist/upgrade/converge.d.ts.map +1 -1
  122. package/dist/upgrade/converge.js +59 -2
  123. package/dist/upgrade/converge.js.map +1 -1
  124. package/dist/upgrade/gcp-lookup.d.ts +6 -0
  125. package/dist/upgrade/gcp-lookup.d.ts.map +1 -1
  126. package/dist/upgrade/gcp-lookup.js +25 -0
  127. package/dist/upgrade/gcp-lookup.js.map +1 -1
  128. package/dist/upgrade/release-images.d.ts +26 -2
  129. package/dist/upgrade/release-images.d.ts.map +1 -1
  130. package/dist/upgrade/release-images.js +35 -2
  131. package/dist/upgrade/release-images.js.map +1 -1
  132. package/dist/upgrade/upgrade.d.ts +5 -0
  133. package/dist/upgrade/upgrade.d.ts.map +1 -1
  134. package/dist/upgrade/upgrade.js +28 -1
  135. package/dist/upgrade/upgrade.js.map +1 -1
  136. package/dist/upgrader-assess.d.ts +85 -0
  137. package/dist/upgrader-assess.d.ts.map +1 -0
  138. package/dist/upgrader-assess.js +122 -0
  139. package/dist/upgrader-assess.js.map +1 -0
  140. package/dist/upgrader-gcp.d.ts +17 -0
  141. package/dist/upgrader-gcp.d.ts.map +1 -0
  142. package/dist/upgrader-gcp.js +87 -0
  143. package/dist/upgrader-gcp.js.map +1 -0
  144. package/dist/upgrader-job.d.ts +133 -0
  145. package/dist/upgrader-job.d.ts.map +1 -0
  146. package/dist/upgrader-job.js +259 -0
  147. package/dist/upgrader-job.js.map +1 -0
  148. package/dist/upgrader-reporter.d.ts +35 -0
  149. package/dist/upgrader-reporter.d.ts.map +1 -0
  150. package/dist/upgrader-reporter.js +79 -0
  151. package/dist/upgrader-reporter.js.map +1 -0
  152. package/dist/upgrader-setup.d.ts +59 -0
  153. package/dist/upgrader-setup.d.ts.map +1 -0
  154. package/dist/upgrader-setup.js +308 -0
  155. package/dist/upgrader-setup.js.map +1 -0
  156. package/dist/wizard.d.ts +6 -0
  157. package/dist/wizard.d.ts.map +1 -1
  158. package/dist/wizard.js +32 -4
  159. package/dist/wizard.js.map +1 -1
  160. package/dist/wizards/gcp-firebase.d.ts +3 -0
  161. package/dist/wizards/gcp-firebase.d.ts.map +1 -1
  162. package/dist/wizards/gcp-firebase.js +1 -0
  163. package/dist/wizards/gcp-firebase.js.map +1 -1
  164. package/dist/wizards/gcp-install-job.d.ts +74 -0
  165. package/dist/wizards/gcp-install-job.d.ts.map +1 -0
  166. package/dist/wizards/gcp-install-job.js +398 -0
  167. package/dist/wizards/gcp-install-job.js.map +1 -0
  168. package/dist/wizards/gcp-prompts.d.ts +3 -0
  169. package/dist/wizards/gcp-prompts.d.ts.map +1 -0
  170. package/dist/wizards/gcp-prompts.js +25 -0
  171. package/dist/wizards/gcp-prompts.js.map +1 -0
  172. package/dist/wizards/gcp-pulumi.d.ts +4 -2
  173. package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
  174. package/dist/wizards/gcp-pulumi.js +1 -1
  175. package/dist/wizards/gcp-pulumi.js.map +1 -1
  176. package/dist/wizards/gcp.d.ts +40 -0
  177. package/dist/wizards/gcp.d.ts.map +1 -1
  178. package/dist/wizards/gcp.js +223 -59
  179. package/dist/wizards/gcp.js.map +1 -1
  180. package/package.json +6 -4
  181. package/src/adapter.ts +97 -0
  182. package/src/adc-impersonation.ts +176 -0
  183. package/src/admin-domain.test.ts +254 -0
  184. package/src/admin-domain.ts +245 -0
  185. package/src/admin-memory.test.ts +151 -0
  186. package/src/agent/apply.test.ts +185 -0
  187. package/src/agent/apply.ts +124 -0
  188. package/src/agent/cli-provenance.test.ts +159 -0
  189. package/src/agent/cli-provenance.ts +191 -0
  190. package/src/agent/command.test.ts +77 -0
  191. package/src/agent/command.ts +564 -0
  192. package/src/agent/config.ts +86 -0
  193. package/src/agent/lock-config.test.ts +97 -0
  194. package/src/agent/lock.ts +110 -0
  195. package/src/agent/queue.test.ts +10 -0
  196. package/src/agent/queue.ts +91 -0
  197. package/src/agent/run.test.ts +437 -0
  198. package/src/agent/run.ts +295 -0
  199. package/src/agent/systemd.ts +209 -0
  200. package/src/agent/units.test.ts +223 -0
  201. package/src/agent/units.ts +163 -0
  202. package/src/azure-front-door.test.ts +119 -0
  203. package/src/azure-front-door.ts +56 -0
  204. package/src/bootstrap-token.ts +20 -0
  205. package/src/caddy.ts +112 -0
  206. package/src/cdn-copy.ts +91 -0
  207. package/src/cert-wait.test.ts +194 -0
  208. package/src/cert-wait.ts +163 -0
  209. package/src/checkpoint-secrets.test.ts +380 -0
  210. package/src/checkpoint-secrets.ts +283 -0
  211. package/src/cli-routing.test.ts +45 -0
  212. package/src/cli-routing.ts +43 -0
  213. package/src/cli.ts +1491 -0
  214. package/src/cloudsql-iam-user.ts +147 -0
  215. package/src/compose.ts +334 -0
  216. package/src/default-firewall.test.ts +411 -0
  217. package/src/default-firewall.ts +342 -0
  218. package/src/deployed-release.test.ts +231 -0
  219. package/src/deployed-release.ts +220 -0
  220. package/src/dns/cloudflare.ts +182 -0
  221. package/src/dns/groups.test.ts +76 -0
  222. package/src/dns/groups.ts +86 -0
  223. package/src/dns/index.ts +56 -0
  224. package/src/dns/manual.ts +130 -0
  225. package/src/dns/types.ts +27 -0
  226. package/src/gateway-credentials.test.ts +180 -0
  227. package/src/gateway-credentials.ts +144 -0
  228. package/src/gcloud-components.test.ts +76 -0
  229. package/src/gcloud-components.ts +85 -0
  230. package/src/gcloud-retry.ts +41 -0
  231. package/src/gcloud-runner.test.ts +61 -0
  232. package/src/gcloud.test.ts +99 -0
  233. package/src/gcloud.ts +322 -0
  234. package/src/gcp-names.ts +135 -0
  235. package/src/index.test.ts +332 -0
  236. package/src/index.ts +114 -0
  237. package/src/infra-contract.ts +32 -0
  238. package/src/install-job-runner.ts +166 -0
  239. package/src/install-job.test.ts +566 -0
  240. package/src/install-job.ts +542 -0
  241. package/src/install-state.test.ts +239 -0
  242. package/src/install-state.ts +583 -0
  243. package/src/internal-token.ts +35 -0
  244. package/src/lifecycle.ts +900 -0
  245. package/src/mcp-iap-stacks.test.ts +58 -0
  246. package/src/mcp-iap.test.ts +149 -0
  247. package/src/mcp-iap.ts +131 -0
  248. package/src/media-volume.test.ts +296 -0
  249. package/src/migration-runner.ts +365 -0
  250. package/src/operator-access-stacks.test.ts +55 -0
  251. package/src/operator-access.test.ts +332 -0
  252. package/src/operator-access.ts +554 -0
  253. package/src/ops-backend.test.ts +320 -0
  254. package/src/ops-backend.ts +414 -0
  255. package/src/provisioner-identity.test.ts +482 -0
  256. package/src/provisioner-identity.ts +407 -0
  257. package/src/redirects-emit.ts +175 -0
  258. package/src/region-data.ts +428 -0
  259. package/src/regions.test.ts +277 -0
  260. package/src/regions.ts +370 -0
  261. package/src/release-contract.ts +57 -0
  262. package/src/release-manifest.test.ts +300 -0
  263. package/src/release-manifest.ts +310 -0
  264. package/src/run-mode.ts +40 -0
  265. package/src/runtime-secrets.test.ts +627 -0
  266. package/src/runtime-secrets.ts +754 -0
  267. package/src/self-command.test.ts +14 -0
  268. package/src/self-command.ts +21 -0
  269. package/src/self-hosted-compose.test.ts +177 -0
  270. package/src/self-hosted-release.ts +240 -0
  271. package/src/self-hosted-roles.integration.test.ts +161 -0
  272. package/src/self-hosted-roles.test.ts +124 -0
  273. package/src/self-hosted-roles.ts +203 -0
  274. package/src/self-hosted-upgrade.test.ts +394 -0
  275. package/src/self-hosted-upgrade.ts +548 -0
  276. package/src/stack-contract-parity.test.ts +199 -0
  277. package/src/stack-contract.test.ts +391 -0
  278. package/src/stack-contract.ts +888 -0
  279. package/src/stack-converge-secrets.test.ts +421 -0
  280. package/src/stack-converge.test.ts +833 -0
  281. package/src/stack-converge.ts +909 -0
  282. package/src/staging-admin.test.ts +246 -0
  283. package/src/staging-admin.ts +324 -0
  284. package/src/state-attach.test.ts +211 -0
  285. package/src/state-attach.ts +132 -0
  286. package/src/state-backend.test.ts +145 -0
  287. package/src/state-backend.ts +262 -0
  288. package/src/state-command.ts +293 -0
  289. package/src/state-migrate.test.ts +479 -0
  290. package/src/state-migrate.ts +434 -0
  291. package/src/state-pulumi.ts +289 -0
  292. package/src/state-store.test.ts +212 -0
  293. package/src/state-store.ts +243 -0
  294. package/src/upgrade/app-roll.ts +486 -0
  295. package/src/upgrade/backup.ts +109 -0
  296. package/src/upgrade/converge.ts +437 -0
  297. package/src/upgrade/gcp-lookup.ts +167 -0
  298. package/src/upgrade/health.test.ts +279 -0
  299. package/src/upgrade/health.ts +305 -0
  300. package/src/upgrade/release-images.test.ts +119 -0
  301. package/src/upgrade/release-images.ts +393 -0
  302. package/src/upgrade/reporter.ts +46 -0
  303. package/src/upgrade/upgrade.test.ts +626 -0
  304. package/src/upgrade/upgrade.ts +249 -0
  305. package/src/upgrader-assess.test.ts +306 -0
  306. package/src/upgrader-assess.ts +250 -0
  307. package/src/upgrader-gcp.ts +123 -0
  308. package/src/upgrader-job.test.ts +411 -0
  309. package/src/upgrader-job.ts +502 -0
  310. package/src/upgrader-reporter.test.ts +46 -0
  311. package/src/upgrader-reporter.ts +105 -0
  312. package/src/upgrader-setup.test.ts +169 -0
  313. package/src/upgrader-setup.ts +355 -0
  314. package/src/wizard.ts +425 -0
  315. package/src/wizards/gcp-cost.ts +188 -0
  316. package/src/wizards/gcp-firebase.ts +72 -0
  317. package/src/wizards/gcp-install-job.ts +506 -0
  318. package/src/wizards/gcp-prompts.ts +26 -0
  319. package/src/wizards/gcp-pulumi.test.ts +246 -0
  320. package/src/wizards/gcp-pulumi.ts +516 -0
  321. package/src/wizards/gcp.ts +1935 -0
@@ -0,0 +1,171 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * Installs, re-pins and removes the agent's systemd --user units (#696
4
+ * Phase 4c). Every command goes through a {@link HostRunner} and the unit
5
+ * directory is a parameter, so tests run against a fake and a temp dir —
6
+ * nothing here touches the real systemd of the machine running the tests.
7
+ *
8
+ * User units stop with the user's last session unless the user "lingers";
9
+ * {@link installAgentUnits} turns lingering on (allowed for oneself on
10
+ * systemd-logind's default policy) and, where it may not, says which one
11
+ * command an administrator runs.
12
+ */
13
+ import { closeSync, ftruncateSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync, writeSync, } from "node:fs";
14
+ import { homedir } from "node:os";
15
+ import { join } from "node:path";
16
+ import { agentServiceUnit, agentTimerUnit, pinnedAgentVersion, } from "./units.js";
17
+ /** The real host: this user's systemd user-unit directory. */
18
+ export function currentAgentHost(runner) {
19
+ const config = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
20
+ return {
21
+ runner,
22
+ unitDir: join(config, "systemd", "user"),
23
+ user: process.env.USER || process.env.LOGNAME || "",
24
+ platform: process.platform,
25
+ };
26
+ }
27
+ /**
28
+ * Why the agent cannot be installed on this host, or null. Linux with a
29
+ * systemd user manager is the supported target; macOS (Docker Desktop) is
30
+ * a development setup, and there `upgrade` is run by hand.
31
+ */
32
+ export async function agentHostProblem(host) {
33
+ if (host.platform !== "linux") {
34
+ return `the update agent runs on Linux hosts with systemd (this is ${host.platform}). Install updates with the upgrade command instead.`;
35
+ }
36
+ const r = await host.runner.run(["systemctl", "--user", "show-environment"]);
37
+ if (r.exitCode !== 0) {
38
+ return `systemd's user manager is not reachable (\`systemctl --user\`: ${r.stderr.trim().slice(0, 200) || `exit ${r.exitCode}`}). Log in to the host as this user directly (not via \`su\`), or install updates with the upgrade command.`;
39
+ }
40
+ return null;
41
+ }
42
+ /** `<unitDir>/<name>.service` + `.timer`. */
43
+ export function agentUnitPaths(host, name) {
44
+ return {
45
+ service: join(host.unitDir, `${name}.service`),
46
+ timer: join(host.unitDir, `${name}.timer`),
47
+ };
48
+ }
49
+ async function systemctl(host, ...args) {
50
+ const r = await host.runner.run(["systemctl", "--user", ...args]);
51
+ return r.exitCode === 0
52
+ ? null
53
+ : `systemctl --user ${args.join(" ")}: ${r.stderr.trim().slice(0, 300) || `exit ${r.exitCode}`}`;
54
+ }
55
+ /**
56
+ * Write both units, reload, enable + start the timer, and make sure the
57
+ * user lingers. Idempotent: re-running rewrites the same files.
58
+ */
59
+ export async function installAgentUnits(spec, host) {
60
+ const paths = agentUnitPaths(host, spec.name);
61
+ try {
62
+ mkdirSync(host.unitDir, { recursive: true });
63
+ writeFileSync(paths.service, agentServiceUnit(spec), { mode: 0o644 });
64
+ writeFileSync(paths.timer, agentTimerUnit(spec), { mode: 0o644 });
65
+ }
66
+ catch (e) {
67
+ return { ok: false, error: `could not write the units: ${e.message}` };
68
+ }
69
+ for (const args of [["daemon-reload"], ["enable", "--now", `${spec.name}.timer`]]) {
70
+ const error = await systemctl(host, ...args);
71
+ if (error)
72
+ return { ok: false, error };
73
+ }
74
+ const warnings = [];
75
+ const linger = await ensureLinger(host);
76
+ if (linger)
77
+ warnings.push(linger);
78
+ return { ok: true, warnings };
79
+ }
80
+ /** Lingering on for the user; returns a warning when it could not be. */
81
+ async function ensureLinger(host) {
82
+ if (!host.user)
83
+ return "could not tell the user name, so lingering was not checked";
84
+ const show = await host.runner.run(["loginctl", "show-user", host.user, "--property=Linger"]);
85
+ if (show.exitCode === 0 && show.stdout.trim() === "Linger=yes")
86
+ return null;
87
+ const enable = await host.runner.run(["loginctl", "enable-linger", host.user]);
88
+ if (enable.exitCode === 0)
89
+ return null;
90
+ return `the agent only runs while ${host.user} is logged in: lingering could not be switched on (${enable.stderr.trim().slice(0, 200) || `exit ${enable.exitCode}`}). Have an administrator run \`sudo loginctl enable-linger ${host.user}\` once.`;
91
+ }
92
+ /** The release the installed service runs, or null when it is not installed. */
93
+ export function installedAgentVersion(host, name) {
94
+ const { service } = agentUnitPaths(host, name);
95
+ try {
96
+ return pinnedAgentVersion(readFileSync(service, "utf8"));
97
+ }
98
+ catch (e) {
99
+ if (e.code === "ENOENT")
100
+ return null;
101
+ throw e;
102
+ }
103
+ }
104
+ /**
105
+ * Re-pin an installed agent to `spec.version` (after an update). Does
106
+ * nothing when the agent is not installed.
107
+ */
108
+ export async function repinAgentUnits(spec, host) {
109
+ const { service } = agentUnitPaths(host, spec.name);
110
+ try {
111
+ // "r+" opens only an existing file (ENOENT otherwise), so the check and
112
+ // the rewrite are one step — no window for the file to change between.
113
+ const fd = openSync(service, "r+");
114
+ try {
115
+ ftruncateSync(fd, 0);
116
+ writeSync(fd, agentServiceUnit(spec), 0, "utf8");
117
+ }
118
+ finally {
119
+ closeSync(fd);
120
+ }
121
+ }
122
+ catch (e) {
123
+ if (e.code === "ENOENT") {
124
+ return { ok: true, warnings: [], installed: false };
125
+ }
126
+ return { ok: false, error: `could not rewrite ${service}: ${e.message}` };
127
+ }
128
+ const error = await systemctl(host, "daemon-reload");
129
+ return error ? { ok: false, error } : { ok: true, warnings: [], installed: true };
130
+ }
131
+ /** Stop + disable the timer and delete both units. */
132
+ export async function uninstallAgentUnits(host, name) {
133
+ const warnings = [];
134
+ const disabled = await systemctl(host, "disable", "--now", `${name}.timer`);
135
+ if (disabled)
136
+ warnings.push(disabled);
137
+ const paths = agentUnitPaths(host, name);
138
+ rmSync(paths.service, { force: true });
139
+ rmSync(paths.timer, { force: true });
140
+ const reload = await systemctl(host, "daemon-reload");
141
+ if (reload)
142
+ warnings.push(reload);
143
+ return { ok: true, warnings };
144
+ }
145
+ /** `systemctl --user status` of both units (text for the terminal). */
146
+ export async function agentUnitStatus(host, name) {
147
+ const r = await host.runner.run([
148
+ "systemctl",
149
+ "--user",
150
+ "--no-pager",
151
+ "status",
152
+ `${name}.timer`,
153
+ `${name}.service`,
154
+ ]);
155
+ // status exits 3 for an inactive oneshot service; the text is what matters.
156
+ return (r.stdout || r.stderr).trim();
157
+ }
158
+ /** The argv that shows the agent's log (journald). */
159
+ export function agentLogsArgv(name, opts) {
160
+ return [
161
+ "journalctl",
162
+ "--user",
163
+ "--no-pager",
164
+ "-u",
165
+ `${name}.service`,
166
+ "-n",
167
+ String(opts.lines),
168
+ ...(opts.follow ? ["-f"] : []),
169
+ ];
170
+ }
171
+ //# sourceMappingURL=systemd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"systemd.js","sourceRoot":"","sources":["../../src/agent/systemd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /** Everything the units name; all paths absolute. */
2
+ export interface AgentUnitSpec {
3
+ /** Unit base name (`caelo-agent-<domain>-<hash>`), see {@link agentUnitName}. */
4
+ readonly name: string;
5
+ readonly domain: string;
6
+ /** The provisioning release the service runs. */
7
+ readonly version: string;
8
+ /** The `bun` binary (the one that ran `init`). */
9
+ readonly bunPath: string;
10
+ /** The install's `.caelo/` directory. */
11
+ readonly caeloDir: string;
12
+ /** Where `.caelo/` lives (the service's working directory). */
13
+ readonly workDir: string;
14
+ /** PATH for the service: docker, cosign and bun must be on it. */
15
+ readonly path: string;
16
+ /** DOCKER_HOST of the installing shell (rootless Docker), when set. */
17
+ readonly dockerHost?: string;
18
+ /**
19
+ * The provenance-verified CLI of {@link version} (agent/cli-provenance.ts)
20
+ * — what an update re-pins the agent to. Without it the service runs the
21
+ * release the operator installed with (`bun x`, as they did by hand).
22
+ */
23
+ readonly cliPath?: string;
24
+ }
25
+ /** The longest a single run (one full upgrade) may take before systemd stops it. */
26
+ export declare const AGENT_RUN_TIMEOUT_MINUTES = 80;
27
+ /**
28
+ * `caelo-agent-<domain>-<hash>`: one agent per install, several installs
29
+ * per host possible. The slug is for people; the hash of the install's
30
+ * `.caelo/` path keeps two installs apart even when their slugs collide
31
+ * (`a.b.example.com` vs `a-b.example.com`).
32
+ */
33
+ export declare function agentUnitName(domain: string, caeloDir: string): string;
34
+ /** The package the service runs, pinned. */
35
+ export declare function agentPackageRef(version: string): string;
36
+ /** The argv of one agent run (also what `agent status` shows). */
37
+ export declare function agentRunArgv(spec: Pick<AgentUnitSpec, "bunPath" | "version" | "cliPath">): string[];
38
+ /** `<name>.service`. */
39
+ export declare function agentServiceUnit(spec: AgentUnitSpec): string;
40
+ /** `<name>.timer`. */
41
+ export declare function agentTimerUnit(spec: Pick<AgentUnitSpec, "name" | "domain">): string;
42
+ /** The release an installed service file runs, or null when it names none. */
43
+ export declare function pinnedAgentVersion(serviceUnit: string): string | null;
44
+ //# sourceMappingURL=units.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"units.d.ts","sourceRoot":"","sources":["../../src/agent/units.ts"],"names":[],"mappings":"AA4BA,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kDAAkD;IAClD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,oFAAoF;AACpF,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAStE;AAED,4CAA4C;AAC5C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKvD;AAmBD,kEAAkE;AAClE,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC,GAC3D,MAAM,EAAE,CAGV;AAED,wBAAwB;AACxB,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAuB5D;AAED,sBAAsB;AACtB,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAG,MAAM,CAoBnF;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMrE"}
@@ -0,0 +1,127 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ /**
3
+ * The systemd units of `caelo-agent` (#696 Phase 4c), as text. Pure, so the
4
+ * exact files are unit-tested; agent/systemd.ts installs them.
5
+ *
6
+ * Why a systemd --user timer on the host, and not a container: the agent
7
+ * has to run `docker compose` for the install, and the only way a container
8
+ * could is the Docker socket — root on the host for anything that gets into
9
+ * that container (Watchtower, the usual answer, was archived in 2025 and
10
+ * verifies no signatures). The agent instead runs as the operator who ran
11
+ * `init`, a member of the `docker` group like that operator already is to
12
+ * run Compose at all; nothing new gets Docker access, and no unit runs as
13
+ * root.
14
+ *
15
+ * Shape: a oneshot service (one poll: heartbeat, then claim and run at most
16
+ * one request) started by a timer every {@link PLATFORM_UPDATE_AGENT_POLL_SECONDS}
17
+ * seconds after the previous run ended — systemd never starts the service
18
+ * while a run (an upgrade can take many minutes) is still active.
19
+ *
20
+ * The service runs the provisioning CLI pinned to an exact release
21
+ * (`bun x --bun @caelo-cms/provisioning@<version> agent run`); a successful
22
+ * update re-pins it to the release it installed.
23
+ */
24
+ import { createHash } from "node:crypto";
25
+ import { PLATFORM_UPDATE_AGENT_POLL_SECONDS } from "@caelo-cms/shared";
26
+ /** The longest a single run (one full upgrade) may take before systemd stops it. */
27
+ export const AGENT_RUN_TIMEOUT_MINUTES = 80;
28
+ /**
29
+ * `caelo-agent-<domain>-<hash>`: one agent per install, several installs
30
+ * per host possible. The slug is for people; the hash of the install's
31
+ * `.caelo/` path keeps two installs apart even when their slugs collide
32
+ * (`a.b.example.com` vs `a-b.example.com`).
33
+ */
34
+ export function agentUnitName(domain, caeloDir) {
35
+ const slug = domain
36
+ .toLowerCase()
37
+ .replace(/[^a-z0-9]+/g, "-")
38
+ .replace(/^-+|-+$/g, "")
39
+ .slice(0, 60);
40
+ if (!slug)
41
+ throw new Error(`cannot name the agent unit after domain ${JSON.stringify(domain)}`);
42
+ const hash = createHash("sha256").update(caeloDir).digest("hex").slice(0, 8);
43
+ return `caelo-agent-${slug}-${hash}`;
44
+ }
45
+ /** The package the service runs, pinned. */
46
+ export function agentPackageRef(version) {
47
+ if (!/^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$/.test(version)) {
48
+ throw new Error(`not a release version: ${JSON.stringify(version)}`);
49
+ }
50
+ return `@caelo-cms/provisioning@${version}`;
51
+ }
52
+ /**
53
+ * One systemd word: double-quoted, `%` escaped (systemd specifiers). Values
54
+ * with a quote, backslash or control character are refused rather than
55
+ * escaped — they are paths and versions, and such a path is a mistake.
56
+ */
57
+ function word(value) {
58
+ if (!value || /["\\\p{Cc}]/u.test(value)) {
59
+ throw new Error(`cannot put ${JSON.stringify(value)} into a systemd unit`);
60
+ }
61
+ return `"${value.replace(/%/g, "%%")}"`;
62
+ }
63
+ /** `Environment="KEY=value"`. */
64
+ function environment(key, value) {
65
+ return `Environment=${word(`${key}=${value}`)}`;
66
+ }
67
+ /** The argv of one agent run (also what `agent status` shows). */
68
+ export function agentRunArgv(spec) {
69
+ if (spec.cliPath)
70
+ return [spec.bunPath, spec.cliPath, "agent", "run"];
71
+ return [spec.bunPath, "x", "--bun", agentPackageRef(spec.version), "agent", "run"];
72
+ }
73
+ /** `<name>.service`. */
74
+ export function agentServiceUnit(spec) {
75
+ return [
76
+ "# SPDX-License-Identifier: MPL-2.0",
77
+ "# Generated by cms-provision (agent install) — do not edit; re-run it instead.",
78
+ "[Unit]",
79
+ `Description=Caelo update agent for ${spec.domain}`,
80
+ "Documentation=https://caelo-cms.com/install-self-hosted",
81
+ "After=network-online.target",
82
+ "",
83
+ "[Service]",
84
+ "Type=oneshot",
85
+ `WorkingDirectory=${word(spec.workDir)}`,
86
+ environment("CAELO_SELF_HOSTED_DIR", spec.caeloDir),
87
+ environment("PATH", spec.path),
88
+ ...(spec.dockerHost ? [environment("DOCKER_HOST", spec.dockerHost)] : []),
89
+ `ExecStart=${agentRunArgv(spec).map(word).join(" ")}`,
90
+ `TimeoutStartSec=${AGENT_RUN_TIMEOUT_MINUTES}min`,
91
+ // Backups, config.json and the lock file: the operator's only.
92
+ "UMask=0077",
93
+ "NoNewPrivileges=yes",
94
+ "Nice=5",
95
+ "",
96
+ ].join("\n");
97
+ }
98
+ /** `<name>.timer`. */
99
+ export function agentTimerUnit(spec) {
100
+ return [
101
+ "# SPDX-License-Identifier: MPL-2.0",
102
+ "# Generated by cms-provision (agent install) — do not edit; re-run it instead.",
103
+ "[Unit]",
104
+ `Description=Poll for Caelo updates for ${spec.domain}`,
105
+ "",
106
+ "[Timer]",
107
+ // The first poll a minute after the timer starts (install, boot);
108
+ // then a minute after each run ends.
109
+ "OnActiveSec=1min",
110
+ "OnBootSec=2min",
111
+ `OnUnitInactiveSec=${PLATFORM_UPDATE_AGENT_POLL_SECONDS}s`,
112
+ "AccuracySec=5s",
113
+ `Unit=${spec.name}.service`,
114
+ "",
115
+ "[Install]",
116
+ "WantedBy=timers.target",
117
+ "",
118
+ ].join("\n");
119
+ }
120
+ /** The release an installed service file runs, or null when it names none. */
121
+ export function pinnedAgentVersion(serviceUnit) {
122
+ const exec = /^ExecStart=.*$/m.exec(serviceUnit)?.[0] ?? "";
123
+ const m = /@caelo-cms\/provisioning@([0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?)"/.exec(exec) ??
124
+ /\/caelo-([0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?)\/node_modules\//.exec(exec);
125
+ return m?.[1] ?? null;
126
+ }
127
+ //# sourceMappingURL=units.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"units.js","sourceRoot":"","sources":["../../src/agent/units.ts"],"names":[],"mappings":"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"}