@underpostnet/cyberia 3.3.0 → 3.3.73

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 (471) hide show
  1. package/.dockerignore +1 -0
  2. package/.github/workflows/coverall.cyberia.ci.yml +34 -14
  3. package/.github/workflows/cyberia-client.cd.yml +5 -0
  4. package/.github/workflows/cyberia-server.cd.yml +5 -0
  5. package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
  6. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
  7. package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
  8. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
  9. package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
  10. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
  11. package/.github/workflows/engine-cyberia.cd.yml +3 -0
  12. package/.github/workflows/engine-cyberia.ci.yml +4 -5
  13. package/.github/workflows/ghpkg.ci.yml +35 -20
  14. package/.github/workflows/hardhat.ci.yml +12 -11
  15. package/.github/workflows/npmpkg.ci.yml +17 -15
  16. package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
  17. package/.github/workflows/release.cd.yml +1 -0
  18. package/.prettierignore +1 -0
  19. package/AGENTS.md +47 -0
  20. package/CHANGELOG.md +565 -2510
  21. package/CLI-HELP.md +306 -147
  22. package/Dockerfile +25 -9
  23. package/Dockerfile.dev +25 -9
  24. package/Dockerfile.test +4 -4
  25. package/README.md +21 -1
  26. package/bin/build.js +66 -41
  27. package/bin/build.template.js +8 -3
  28. package/bin/cyberia.js +308 -91
  29. package/bin/deploy.js +18 -104
  30. package/bin/index.js +308 -91
  31. package/conf.js +91 -4
  32. package/deploy/cyberia-client/deploy.sh +47 -0
  33. package/deploy/cyberia-client/package.sh +18 -0
  34. package/deploy/cyberia-client/state.sh +14 -0
  35. package/deploy/cyberia-server/deploy.sh +47 -0
  36. package/deploy/cyberia-server/package.sh +18 -0
  37. package/deploy/cyberia-server/state.sh +14 -0
  38. package/deploy/dd-cyberia/deploy.sh +6 -26
  39. package/deploy/dd-cyberia/init.sh +35 -43
  40. package/deploy/dd-cyberia/package.sh +17 -0
  41. package/deploy/dd-cyberia/state.sh +14 -0
  42. package/deploy/dd-cyberia/sync-deploy.sh +92 -170
  43. package/deploy/lib/github-actions-logging.sh +594 -0
  44. package/deploy/lib/host.sh +185 -0
  45. package/deploy/lib/state.sh +62 -0
  46. package/deploy/pwa-microservices-template/deploy.sh +12 -39
  47. package/deploy/release/deploy.sh +9 -39
  48. package/deployment.yaml +7 -2
  49. package/docker-compose.yml +7 -7
  50. package/examples/static-page/README.md +19 -19
  51. package/examples/static-page/ssr-components/CustomPage.js +2 -2
  52. package/hardhat/hardhat.config.js +1 -6
  53. package/hardhat/package-lock.json +101 -40
  54. package/hardhat/package.json +2 -2
  55. package/manifests/alertmanager/deployment.yaml +81 -0
  56. package/manifests/blackbox-exporter/deployment.yaml +75 -0
  57. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +32 -7
  58. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +32 -7
  59. package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
  60. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  61. package/manifests/grafana/deployment.yaml +26 -7
  62. package/manifests/grafana/kustomization.yaml +1 -0
  63. package/manifests/grafana/service.yaml +6 -1
  64. package/manifests/mariadb/pv.yaml +1 -0
  65. package/manifests/mongodb/statefulset.yaml +9 -2
  66. package/manifests/mysql/pv-pvc.yaml +14 -1
  67. package/manifests/postgresql/pv.yaml +12 -1
  68. package/manifests/postgresql/pvc.yaml +1 -0
  69. package/manifests/prometheus/deployment.yaml +18 -22
  70. package/package.json +83 -10
  71. package/scripts/event-monitor.sh +56 -0
  72. package/scripts/k3s-node-setup.sh +27 -14
  73. package/scripts/kubeadm-node-setup.sh +31 -11
  74. package/scripts/maas-setup.sh +8 -8
  75. package/scripts/selinux-normalize.sh +907 -0
  76. package/scripts/shutdown-machine.sh +843 -0
  77. package/scripts/test-monitor.sh +3 -3
  78. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +1 -1
  79. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +2 -2
  80. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +2 -2
  81. package/src/api/core/core.controller.js +1 -1
  82. package/src/api/core/core.router.js +2 -2
  83. package/src/api/core/core.service.js +2 -2
  84. package/src/api/crypto/crypto.controller.js +1 -1
  85. package/src/api/crypto/crypto.service.js +1 -1
  86. package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
  87. package/src/api/cyberia-action/cyberia-action.router.js +1 -1
  88. package/src/api/cyberia-action/cyberia-action.service.js +2 -2
  89. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -1
  90. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +1 -1
  91. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +2 -2
  92. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
  93. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
  94. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
  95. package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
  96. package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
  97. package/src/api/cyberia-entity/cyberia-entity.service.js +2 -2
  98. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +1 -1
  99. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +1 -1
  100. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +2 -2
  101. package/src/api/cyberia-instance/cyberia-fallback-capture.js +466 -0
  102. package/src/api/cyberia-instance/cyberia-fallback-world.js +8 -0
  103. package/src/api/cyberia-instance/cyberia-instance-map.service.js +1 -1
  104. package/src/api/cyberia-instance/cyberia-instance.controller.js +1 -1
  105. package/src/api/cyberia-instance/cyberia-instance.router.js +2 -2
  106. package/src/api/cyberia-instance/cyberia-instance.service.js +2 -2
  107. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
  108. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
  109. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +2 -2
  110. package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
  111. package/src/api/cyberia-map/cyberia-map.router.js +1 -1
  112. package/src/api/cyberia-map/cyberia-map.service.js +2 -2
  113. package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
  114. package/src/api/cyberia-quest/cyberia-quest.router.js +1 -1
  115. package/src/api/cyberia-quest/cyberia-quest.service.js +2 -2
  116. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
  117. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
  118. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
  119. package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
  120. package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
  121. package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
  122. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +0 -26
  123. package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
  124. package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
  125. package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
  126. package/src/api/default/default.controller.js +1 -1
  127. package/src/api/default/default.router.js +1 -1
  128. package/src/api/default/default.service.js +2 -2
  129. package/src/api/document/document.controller.js +1 -1
  130. package/src/api/document/document.router.js +1 -1
  131. package/src/api/document/document.service.js +2 -2
  132. package/src/api/file/file.controller.js +1 -1
  133. package/src/api/file/file.router.js +1 -1
  134. package/src/api/file/file.service.js +2 -2
  135. package/src/api/instance/instance.controller.js +1 -1
  136. package/src/api/instance/instance.router.js +1 -1
  137. package/src/api/instance/instance.service.js +2 -2
  138. package/src/api/ipfs/ipfs.controller.js +1 -1
  139. package/src/api/ipfs/ipfs.router.js +2 -2
  140. package/src/api/ipfs/ipfs.service.js +2 -2
  141. package/src/api/object-layer/object-layer.controller.js +1 -1
  142. package/src/api/object-layer/object-layer.router.js +2 -2
  143. package/src/api/object-layer/object-layer.service.js +3 -3
  144. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
  145. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
  146. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
  147. package/src/api/test/test.controller.js +1 -1
  148. package/src/api/test/test.service.js +1 -1
  149. package/src/api/user/guest.service.js +3 -3
  150. package/src/api/user/user.controller.js +1 -1
  151. package/src/api/user/user.router.js +2 -2
  152. package/src/api/user/user.service.js +4 -4
  153. package/src/api.js +5 -9
  154. package/src/cli/app.js +391 -0
  155. package/src/cli/baremetal.js +30 -35
  156. package/src/cli/client.js +306 -0
  157. package/src/cli/cloud-init.js +3 -3
  158. package/src/cli/cluster.js +184 -82
  159. package/src/cli/db.js +120 -68
  160. package/src/cli/deploy.js +153 -71
  161. package/src/cli/docker-compose.js +5 -5
  162. package/src/cli/domains.js +184 -0
  163. package/src/cli/dotenv-store.js +143 -0
  164. package/src/cli/event.js +2281 -0
  165. package/src/cli/fs.js +3 -3
  166. package/src/cli/host.js +672 -0
  167. package/src/cli/image.js +4 -6
  168. package/src/cli/index.js +322 -142
  169. package/src/cli/ipfs.js +34 -30
  170. package/src/cli/kickstart.js +1 -1
  171. package/src/cli/kubectl.js +218 -41
  172. package/src/cli/lxd.js +3 -3
  173. package/src/cli/monitor.js +1359 -26
  174. package/src/cli/package.js +90 -0
  175. package/src/cli/release.js +16 -12
  176. package/src/cli/repository.js +558 -363
  177. package/src/cli/run.js +331 -650
  178. package/src/cli/secrets.js +2158 -964
  179. package/src/cli/ssh.js +478 -279
  180. package/src/cli/state.js +394 -0
  181. package/src/cli/static.js +2 -2
  182. package/src/cli/system.js +1 -1
  183. package/src/cli/test.js +199 -125
  184. package/src/cli/vultr.js +61 -21
  185. package/src/cli/wireguard.js +1111 -306
  186. package/src/client/components/core/CalendarCore.js +53 -96
  187. package/src/client/components/core/Docs.js +258 -211
  188. package/src/client/components/core/FileExplorer.js +0 -21
  189. package/src/client/components/core/PanelForm.js +4 -4
  190. package/src/client/components/core/Repository.js +56 -0
  191. package/src/client/components/core/Translate.js +7 -0
  192. package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
  193. package/src/client/components/core/Wallet.js +0 -11
  194. package/src/client/components/core/Worker.js +7 -1
  195. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
  196. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +2 -1
  197. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
  198. package/src/client/components/default/AppShellDefault.js +1 -1
  199. package/src/client/components/default/SettingsDefault.js +2 -2
  200. package/src/client/components/itemledger/SettingsItemledger.js +2 -2
  201. package/src/client/components/underpost/AppShellUnderpost.js +3 -2
  202. package/src/client/components/underpost/SettingsUnderpost.js +2 -2
  203. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +32 -5
  204. package/src/client/public/cyberia-docs/CYBERIA.md +21 -1
  205. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
  206. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  207. package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
  208. package/src/client/public/default/android-chrome-144x144.png +0 -0
  209. package/src/client/public/default/android-chrome-192x192.png +0 -0
  210. package/src/client/public/default/android-chrome-256x256.png +0 -0
  211. package/src/client/public/default/android-chrome-36x36.png +0 -0
  212. package/src/client/public/default/android-chrome-384x384.png +0 -0
  213. package/src/client/public/default/android-chrome-48x48.png +0 -0
  214. package/src/client/public/default/android-chrome-512x512.png +0 -0
  215. package/src/client/public/default/android-chrome-72x72.png +0 -0
  216. package/src/client/public/default/android-chrome-96x96.png +0 -0
  217. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  218. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  219. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  220. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  221. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  222. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  223. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  224. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  225. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  226. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  227. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  228. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  229. package/src/client/public/default/apple-touch-icon.png +0 -0
  230. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  231. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  232. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  233. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  234. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  235. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  236. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  237. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  238. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  239. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  240. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  241. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  242. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  243. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  244. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  245. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  246. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  247. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  248. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  249. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  250. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  251. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  252. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  253. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  254. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  255. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  256. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  257. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  258. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  259. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  260. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  261. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  262. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  263. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  264. package/src/client/public/default/assets/background/white.jpg +0 -0
  265. package/src/client/public/default/browserconfig.xml +1 -1
  266. package/src/client/public/default/favicon-16x16.png +0 -0
  267. package/src/client/public/default/favicon-32x32.png +0 -0
  268. package/src/client/public/default/favicon-48x48.png +0 -0
  269. package/src/client/public/default/favicon.ico +0 -0
  270. package/src/client/public/default/manifest.webmanifest +5 -5
  271. package/src/client/public/default/mstile-144x144.png +0 -0
  272. package/src/client/public/default/mstile-150x150.png +0 -0
  273. package/src/client/public/default/mstile-310x150.png +0 -0
  274. package/src/client/public/default/mstile-310x310.png +0 -0
  275. package/src/client/public/default/mstile-70x70.png +0 -0
  276. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  277. package/src/client/public/default/yandex-browser-manifest.json +1 -1
  278. package/src/client/ssr/RootDocument.js +1 -1
  279. package/src/client/ssr/body/404.js +1 -1
  280. package/src/client/ssr/body/500.js +1 -1
  281. package/src/client/ssr/body/CacheControl.js +1 -1
  282. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
  283. package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
  284. package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
  285. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
  286. package/src/client/ssr/head/CryptokoynScripts.js +1 -1
  287. package/src/client/ssr/head/Css.js +1 -1
  288. package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
  289. package/src/client/ssr/head/DefaultScripts.js +1 -1
  290. package/src/client/ssr/head/ItemledgerScripts.js +1 -1
  291. package/src/client/ssr/head/Microdata.js +1 -1
  292. package/src/client/ssr/head/Production.js +1 -1
  293. package/src/client/ssr/head/Pwa.js +1 -1
  294. package/src/client/ssr/head/PwaItemledger.js +1 -1
  295. package/src/client/ssr/head/Seo.js +1 -1
  296. package/src/client/ssr/head/UnderpostScripts.js +1 -1
  297. package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
  298. package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
  299. package/src/client/ssr/views/Cyberia404.js +7 -5
  300. package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
  301. package/src/client/ssr/views/Maintenance.js +1 -1
  302. package/src/client/ssr/views/NoNetworkConnection.js +1 -1
  303. package/src/client/ssr/views/Test.js +1 -1
  304. package/src/client/sw/core.sw.js +20 -14
  305. package/src/client-builder/client-build-docs.js +61 -46
  306. package/src/client-builder/client-build-live.js +2 -2
  307. package/src/client-builder/client-build.js +38 -30
  308. package/src/client-builder/client-dev-server.js +3 -3
  309. package/src/client-builder/client-icons.js +2 -2
  310. package/src/client-builder/ssr.js +3 -3
  311. package/src/client.build.js +3 -6
  312. package/src/client.dev.js +3 -6
  313. package/src/db/DataBaseProvider.js +186 -3
  314. package/src/db/mariadb/MariaDB.js +3 -2
  315. package/src/db/mongo/MongoBootstrap.js +273 -101
  316. package/src/db/mongo/MongooseDB.js +7 -8
  317. package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
  318. package/src/grpc/cyberia/grpc-server.js +1 -1
  319. package/src/index.js +79 -23
  320. package/src/mailer/EmailRender.js +2 -2
  321. package/src/mailer/MailerInterceptor.js +87 -0
  322. package/src/mailer/MailerProvider.js +50 -6
  323. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +1 -1
  324. package/src/projects/cyberia/besu-genesis-generator.js +3 -3
  325. package/src/projects/cyberia/catalog-cyberia.js +53 -10
  326. package/src/projects/cyberia/gemini-client.js +1 -1
  327. package/src/projects/cyberia/generate-saga.js +1 -1
  328. package/src/projects/cyberia/hot-reload-trigger.js +1 -1
  329. package/src/projects/cyberia/instance-data.js +1 -1
  330. package/src/projects/cyberia/ipfs-client.js +4 -4
  331. package/src/projects/cyberia/map-preview-generator.js +1 -1
  332. package/src/projects/cyberia/object-layer.js +1 -1
  333. package/src/projects/cyberia/semantic-layer-generator.js +1 -1
  334. package/src/projects/underpost/catalog-underpost.js +9 -1
  335. package/src/proxy.js +4 -7
  336. package/src/runtime/cyberia-client/Dockerfile +9 -4
  337. package/src/runtime/cyberia-client/Dockerfile.dev +8 -2
  338. package/src/runtime/cyberia-server/Dockerfile +9 -4
  339. package/src/runtime/cyberia-server/Dockerfile.dev +8 -2
  340. package/src/runtime/engine-cyberia/Dockerfile +25 -9
  341. package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
  342. package/src/runtime/engine-cyberia/Dockerfile.test +4 -4
  343. package/src/runtime/engine-cyberia/docker-compose.yml +7 -7
  344. package/src/runtime/express/Express.js +32 -27
  345. package/src/runtime/lampp/Lampp.js +22 -70
  346. package/src/runtime/nginx/Nginx.js +1 -1
  347. package/src/runtime/wp/Wp.js +16 -48
  348. package/src/server/{catalog.js → build/catalog.js} +15 -5
  349. package/src/server/build/coverage.js +117 -0
  350. package/src/server/build/execution.js +402 -0
  351. package/src/server/build/package.js +465 -0
  352. package/src/server/build/testing.js +528 -0
  353. package/src/server/{dns.js → network/dns.js} +144 -11
  354. package/src/server/{forward-proxy.js → network/forward-proxy.js} +10 -18
  355. package/src/server/{middlewares.js → network/middlewares.js} +3 -3
  356. package/src/server/network/node-capability.js +98 -0
  357. package/src/server/{peer.js → network/peer.js} +3 -3
  358. package/src/server/{proxy.js → network/proxy.js} +7 -13
  359. package/src/server/network/router.js +356 -0
  360. package/src/server/{tls.js → network/tls.js} +2 -2
  361. package/src/server/{underpost-compression.js → network/underpost-compression.js} +1 -1
  362. package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +7 -7
  363. package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +2 -2
  364. package/src/server/{cri.js → ops/cri.js} +2 -2
  365. package/src/server/{cron.js → ops/cron.js} +349 -74
  366. package/src/server/ops/event-notification.js +284 -0
  367. package/src/server/{logger.js → ops/logger.js} +108 -23
  368. package/src/server/ops/monitoring.js +1724 -0
  369. package/src/server/{systemd.js → ops/systemd.js} +55 -1
  370. package/src/server/{conf.js → runtime/conf.js} +513 -422
  371. package/src/server/runtime/config-scope.js +215 -0
  372. package/src/server/runtime/environment.js +149 -0
  373. package/src/server/{process.js → runtime/process.js} +153 -12
  374. package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
  375. package/src/server/{runtime.js → runtime/runtime.js} +12 -8
  376. package/src/server/{start.js → runtime/start.js} +128 -39
  377. package/src/server/{auth.js → security/auth.js} +7 -8
  378. package/src/server/security/container-storage.js +382 -0
  379. package/src/server/{crypto.js → security/crypto.js} +1 -1
  380. package/src/server/{selinux.js → security/selinux.js} +1 -1
  381. package/src/server/{backup.js → storage/backup.js} +17 -8
  382. package/src/server/{data-query.js → storage/data-query.js} +1 -1
  383. package/src/server/{downloader.js → storage/downloader.js} +2 -2
  384. package/src/server/storage/repository.js +68 -0
  385. package/src/server.js +4 -7
  386. package/src/ws/IoInterface.js +1 -1
  387. package/src/ws/IoServer.js +1 -1
  388. package/src/ws/core/core.ws.connection.js +1 -1
  389. package/src/ws/core/core.ws.emit.js +1 -1
  390. package/src/ws/core/core.ws.server.js +1 -1
  391. package/src/ws/default/default.ws.connection.js +1 -1
  392. package/src/ws/default/default.ws.emit.js +1 -1
  393. package/src/ws/default/default.ws.server.js +1 -1
  394. package/test/e2e/event-e2e-public-ingress-down.js +45 -0
  395. package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
  396. package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
  397. package/test/{api.test.js → integration/app/api.test.js} +33 -14
  398. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +30 -0
  399. package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +1 -1
  400. package/test/integration/app/cyberia/cyberia-load.test.js +467 -0
  401. package/test/integration/app/cyberia/fallback-world-capture.test.js +253 -0
  402. package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
  403. package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
  404. package/test/integration/infra/1-security/config-scope.test.js +305 -0
  405. package/test/integration/infra/1-security/container-storage.test.js +356 -0
  406. package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
  407. package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
  408. package/test/{selinux.test.js → integration/infra/1-security/selinux.test.js} +2 -4
  409. package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
  410. package/test/integration/infra/1-security/systemd-service.test.js +70 -0
  411. package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
  412. package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
  413. package/test/integration/infra/2-network/node-capability.test.js +182 -0
  414. package/test/integration/infra/2-network/wireguard-cli.test.js +1163 -0
  415. package/test/{wireguard-edge.test.js → integration/infra/2-network/wireguard-edge.test.js} +609 -55
  416. package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
  417. package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
  418. package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
  419. package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
  420. package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
  421. package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
  422. package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +6 -6
  423. package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +4 -4
  424. package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
  425. package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
  426. package/test/integration/infra/5-observability/event-notification.test.js +197 -0
  427. package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
  428. package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
  429. package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
  430. package/test/support/shell-harness.js +73 -0
  431. package/test/unit/build-template.test.js +97 -0
  432. package/test/unit/build-workflow-offline.test.js +132 -0
  433. package/test/unit/catalog.test.js +71 -0
  434. package/test/unit/client-build-docs.test.js +334 -0
  435. package/test/unit/conf-loading.test.js +303 -0
  436. package/test/unit/conf-resolution.test.js +979 -0
  437. package/test/unit/coverage-artifact.test.js +130 -0
  438. package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
  439. package/test/unit/deploy-env-resolution.test.js +38 -0
  440. package/test/unit/deploy-log-table.test.js +447 -0
  441. package/test/unit/execution-profiles.test.js +219 -0
  442. package/test/unit/fleet-sync-source.test.js +149 -0
  443. package/test/unit/logger-redaction.test.js +112 -0
  444. package/test/unit/package.test.js +403 -0
  445. package/test/unit/prepare-host.test.js +299 -0
  446. package/test/unit/process-environment.test.js +18 -0
  447. package/test/unit/propagation-message.test.js +78 -0
  448. package/test/unit/redeploy-plan.test.js +24 -0
  449. package/test/unit/release-bump.test.js +474 -0
  450. package/test/unit/ssh-output-redaction.test.js +28 -0
  451. package/test/unit/start-options.test.js +46 -0
  452. package/test/unit/test-tiers.test.js +193 -0
  453. package/vitest.config.js +58 -0
  454. package/.nycrc +0 -9
  455. package/deploy/lib/logging.sh +0 -96
  456. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
  457. package/manifests/mongodb/pv-pvc.yaml +0 -59
  458. package/scripts/coverall-test-cyberia.sh +0 -24
  459. package/scripts/coverall-test.sh +0 -24
  460. package/scripts/link-local-underpost-cli.sh +0 -6
  461. package/src/api/user/user.build.js +0 -16
  462. package/src/cli/env.js +0 -177
  463. package/src/client/components/core/Blockchain.js +0 -41
  464. package/src/client/components/core/Blog.js +0 -9
  465. package/src/client/components/core/KeyboardAvoidance.js +0 -145
  466. package/src/client/public/default/assets/background/dark.jpg +0 -0
  467. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  468. package/src/client/public/default/assets/background/white0.jpg +0 -0
  469. package/src/client/public/doc/favicon.ico +0 -0
  470. package/src/client/public/doc/sitemap +0 -148
  471. package/src/server/environment.js +0 -98
@@ -0,0 +1,299 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @module prepare-host.test
5
+ * @description Covers the step order `prepare_host` in `deploy/lib/host.sh` emits. Drives the real
6
+ * shell helper with `deploy_step` stubbed out, so nothing is executed — no host, no root.
7
+ *
8
+ * Uses 'chai' for assertions.
9
+ */
10
+
11
+ import { expect } from 'chai';
12
+ import { execFileSync } from 'node:child_process';
13
+ import fs from 'fs-extra';
14
+ import os from 'node:os';
15
+ import path from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+
18
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
19
+ const hostLib = path.join(repoRoot, 'deploy/lib/host.sh');
20
+ // Defined before and after the source: the library pulls in the real logging helpers, which
21
+ // would otherwise run the steps instead of printing them.
22
+ const STUB = `deploy_step() { printf '%s :: %s\\n' "$1" "${'$'}{*:2}"; };`;
23
+
24
+ const steps = () =>
25
+ execFileSync(
26
+ 'bash',
27
+ [
28
+ '-c',
29
+ `deploy_step() { printf '%s :: %s\\n' "$1" "${'$'}{*:2}"; }; source "${hostLib}"; ` +
30
+ `prepare_host /home/dd/engine owner/engine owner/engine-private`,
31
+ ],
32
+ { encoding: 'utf8' },
33
+ )
34
+ .trim()
35
+ .split('\n');
36
+
37
+ describe('a node installs the deploy own package manifest', () => {
38
+ const run = (script) =>
39
+ execFileSync('bash', ['-c', `${STUB} source "${hostLib}"; ${STUB} ${script}`], {
40
+ encoding: 'utf8',
41
+ });
42
+
43
+ it('resolves the deploy id from the source repository, without running the CLI', () => {
44
+ // The manifest this resolves is what makes the CLI runnable, so it cannot be resolved by
45
+ // asking the CLI. Test and production sources of one deploy answer the same id.
46
+ const resolved = run(
47
+ 'for r in owner/engine-test-cyberia owner/engine-cyberia owner/engine-cyberia-private owner/engine; ' +
48
+ 'do printf "[%s]" "$(deploy_id_from_repo "$r")"; done',
49
+ );
50
+ expect(resolved.trim()).to.equal('[dd-cyberia][dd-cyberia][dd-cyberia][]');
51
+ });
52
+
53
+ it('installs from engine-private/conf/<deploy-id>/package.json, on both sides of the pull', () => {
54
+ // Regression: a product checkout declares only what it publishes, so installing against its
55
+ // own manifest pruned packages the CLI imports — and the CLI is what pulls the checkout.
56
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'underpost-prepare-host-'));
57
+ try {
58
+ fs.outputFileSync(path.join(root, 'engine-private/conf/dd-x/package.json'), '{}');
59
+ const emitted = run(`prepare_host ${root} owner/engine-x owner/engine-private`).trim().split('\n');
60
+ const titles = emitted.map((line) => line.split(' :: ')[0]);
61
+
62
+ expect(titles).to.deep.equal([
63
+ 'Install dependencies (dd-x)',
64
+ 'Link underpost CLI',
65
+ 'Pull repository',
66
+ 'Install dependencies (dd-x)',
67
+ 'Link underpost CLI',
68
+ 'Load host config',
69
+ ]);
70
+ for (const index of [0, 3])
71
+ expect(emitted[index]).to.include(
72
+ 'cp -a ./engine-private/conf/dd-x/package.json ./package.json && npm install',
73
+ );
74
+ } finally {
75
+ fs.removeSync(root);
76
+ }
77
+ });
78
+
79
+ it('installs the checkout own manifest when the deploy ships none', () => {
80
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'underpost-prepare-host-'));
81
+ try {
82
+ const emitted = run(`install_deploy_dependencies ${root} dd-absent`).trim().split('\n');
83
+ expect(emitted[0]).to.equal(`Install dependencies :: sudo -n -- /bin/bash -lc cd ${root} && npm install`);
84
+ expect(emitted[1]).to.include(`Link underpost CLI :: sudo -n -- /bin/bash -lc cd ${root} && npm link --force`);
85
+ } finally {
86
+ fs.removeSync(root);
87
+ }
88
+ });
89
+ });
90
+
91
+ describe('a node prepares itself from the source its host configuration names', () => {
92
+ // `npm root -g` is stubbed rather than the file read: the store's location is the one thing
93
+ // the helper resolves, and a test that writes into the real global tree is not a unit test.
94
+ const sources = (store) =>
95
+ execFileSync(
96
+ 'bash',
97
+ [
98
+ '-c',
99
+ `npm() { printf '%s\\n' "${store}"; }; source "${hostLib}"; ` +
100
+ 'printf "[%s][%s]" "$ENGINE_SRC_REPO" "$ENGINE_SRC_PRIVATE_REPO"',
101
+ ],
102
+ { encoding: 'utf8', env: { ...process.env, ENGINE_SRC_REPO: '', ENGINE_SRC_PRIVATE_REPO: '' } },
103
+ );
104
+
105
+ it('reads the pair `wireguard --sync` recorded, over the built-in fallback', () => {
106
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'underpost-host-config-'));
107
+ try {
108
+ fs.outputFileSync(
109
+ path.join(root, 'underpost/.env'),
110
+ 'GITHUB_TOKEN=secret\nENGINE_SRC_REPO="owner/engine-test-lampp"\nENGINE_SRC_PRIVATE_REPO=owner/engine-lampp-private\n',
111
+ );
112
+ expect(sources(root)).to.equal('[owner/engine-test-lampp][owner/engine-lampp-private]');
113
+ } finally {
114
+ fs.removeSync(root);
115
+ }
116
+ });
117
+
118
+ it('names no repository of its own, leaving the pairing to the pull that resolves it', () => {
119
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'underpost-host-config-'));
120
+ try {
121
+ expect(sources(root)).to.equal('[][]');
122
+ } finally {
123
+ fs.removeSync(root);
124
+ }
125
+ });
126
+
127
+ it('lets the environment override the store, which is how a deploy script retargets a node', () => {
128
+ const emitted = execFileSync('bash', ['-c', `source "${hostLib}"; printf '%s' "$(deploy_id_from_repo)"`], {
129
+ encoding: 'utf8',
130
+ env: { ...process.env, ENGINE_SRC_REPO: 'owner/engine-test-core' },
131
+ });
132
+ expect(emitted).to.equal('dd-core');
133
+ });
134
+ });
135
+
136
+ const deployRoot = path.join(repoRoot, 'deploy');
137
+ // The base template restores `deploy/lib` and nothing that deploys, so a checkout carrying no
138
+ // deploy id of its own has no manifest script to hold to this contract. Read as "ships deploy
139
+ // ids", not as "the filter below found something" — that stays an assertion, not a skip.
140
+ const shipsDeployIds = fs.existsSync(deployRoot) && fs.readdirSync(deployRoot).some((e) => e.startsWith('dd-'));
141
+
142
+ describe.skipIf(!shipsDeployIds)('every deploy ships a package script for its own manifest', () => {
143
+ // A deploy id directory is one that carries a deploy script; lib/ and the project-scope
144
+ // directories are not deployments.
145
+ const deployDirectories = fs
146
+ .readdirSync(deployRoot)
147
+ .filter((entry) => fs.existsSync(path.join(deployRoot, entry, 'sync-deploy.sh')) || entry.startsWith('cyberia-'));
148
+
149
+ it('covers every deploy id and instance directory', () => {
150
+ expect(deployDirectories).to.not.be.empty;
151
+ for (const directory of deployDirectories)
152
+ expect(fs.existsSync(path.join(deployRoot, directory, 'package.sh')), directory).to.equal(true);
153
+ });
154
+
155
+ it('names a deploy id and does nothing but install its manifest', () => {
156
+ for (const directory of deployDirectories) {
157
+ const source = fs.readFileSync(path.join(deployRoot, directory, 'package.sh'), 'utf8');
158
+ expect(source, directory).to.match(/^DEPLOY_ID=dd-[a-z0-9-]+$/m);
159
+ expect(source, directory).to.include('install_deploy_dependencies "$ENGINE_ROOT" "$DEPLOY_ID"');
160
+ expect(source, directory).to.not.include('kubectl');
161
+ }
162
+ });
163
+ });
164
+
165
+ describe('node bootstrap installs a runtime a unit can execute', () => {
166
+ // Regression: both scripts said "home-directory runtimes cannot be used by hardened systemd
167
+ // services under SELinux" and then gated on `command -v node`, which an nvm runtime under $HOME
168
+ // satisfies. A node whose operator had nvm Node 24 on PATH was left with no system Node at all,
169
+ // and every supervised service failed 203/EXEC with nothing able to repair it.
170
+ const scripts = ['scripts/kubeadm-node-setup.sh', 'scripts/k3s-node-setup.sh'];
171
+
172
+ it('decides on a system path rather than on whatever is on PATH', () => {
173
+ for (const script of scripts) {
174
+ const source = fs.readFileSync(path.join(repoRoot, script), 'utf8');
175
+ expect(source, script).to.include('system_node_path()');
176
+ expect(source, script).to.include('/usr/bin/node /usr/local/bin/node /bin/node');
177
+ expect(source, script).to.not.match(/^\s*if.*command -v node .*grep -q .\^v24/m);
178
+ }
179
+ });
180
+
181
+ it('resolves only an executable Node 24 at a system path', () => {
182
+ // The candidate paths are faked under a temp root rather than the real /usr/bin, /usr/local/bin,
183
+ // /bin: the host running this suite may itself have a genuine system Node 24 at one of those
184
+ // paths, which would make the probe correctly resolve it and defeat the regression check below.
185
+ const probe = (bin, candidates) =>
186
+ execFileSync(
187
+ 'bash',
188
+ [
189
+ '-c',
190
+ 'set -euo pipefail; system_node_path() { local c; for c in ' +
191
+ candidates +
192
+ '; do if [ -x "$c" ] && "$c" --version 2>/dev/null | grep -q "^v24"; then printf "%s" "$c"; return 0; fi; ' +
193
+ `done; return 1; }; PATH=${bin}:$PATH; if p="$(system_node_path)"; then printf 'system:%s' "$p"; ` +
194
+ "else printf 'none'; fi",
195
+ ],
196
+ { encoding: 'utf8' },
197
+ );
198
+
199
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'underpost-nvm-'));
200
+ try {
201
+ const home = path.join(root, 'home');
202
+ const candidates = ['/usr/bin', '/usr/local/bin', '/bin'].map((d) => path.join(root, 'fake', d, 'node'));
203
+
204
+ // A Node 24 reachable only through PATH, the way nvm publishes one, resolves to nothing.
205
+ fs.outputFileSync(path.join(home, 'node'), '#!/bin/sh\necho v24.15.0\n');
206
+ fs.chmodSync(path.join(home, 'node'), 0o755);
207
+ expect(probe(home, candidates.join(' '))).to.equal('none');
208
+ } finally {
209
+ fs.removeSync(root);
210
+ }
211
+ });
212
+ });
213
+
214
+ describe('the pod bootstrap can write what it installs', () => {
215
+ const bootstrap = (args) =>
216
+ execFileSync('bash', ['-c', `source "${hostLib}"; pod_bootstrap_cmd ${args}`], { encoding: 'utf8' })
217
+ .split(',')
218
+ .map((step) => step.trim());
219
+
220
+ it('takes the global npm prefix before installing or linking into it', () => {
221
+ // Regression: the manifest's `install` hook installs global tooling and `npm link` publishes
222
+ // the CLI there, and the image leaves that tree owned by root — both failed with EACCES.
223
+ const steps = bootstrap('dd-cyberia production owner/engine-test-cyberia');
224
+ const grant = steps.findIndex((step) => step.startsWith('sudo chown -R'));
225
+
226
+ expect(grant, 'ownership of the npm prefix').to.be.greaterThan(-1);
227
+ expect(steps[grant]).to.include('$(npm prefix -g)/lib/node_modules');
228
+ expect(steps[grant]).to.include('$(npm prefix -g)/bin');
229
+ // Resolved in the container, by the user the container runs as.
230
+ expect(steps[grant]).to.include('$(id -u):$(id -g)');
231
+ expect(grant).to.be.lessThan(steps.indexOf('npm install'));
232
+ expect(steps.indexOf('npm install')).to.be.lessThan(steps.indexOf('npm link --force'));
233
+ const verifyLink = steps.findIndex((step) => step.includes('command -v underpost'));
234
+ const setStatus = steps.findIndex((step) => step.startsWith('underpost state set'));
235
+ expect(verifyLink, 'linked underpost path verification').to.be.greaterThan(steps.indexOf('npm link --force'));
236
+ expect(verifyLink).to.be.lessThan(setStatus);
237
+ expect(steps[verifyLink]).to.include('readlink -f ./bin/index.js');
238
+ });
239
+ });
240
+
241
+ describe('has_changes reads a checkout the caller names', () => {
242
+ const query = (call) =>
243
+ execFileSync('bash', ['-c', `source "${hostLib}"; sudo() { printf '%s\\n' "$*"; }; ${call}`], {
244
+ encoding: 'utf8',
245
+ }).trim();
246
+
247
+ it('takes the engine root as an argument, and falls back to the caller own root', () => {
248
+ expect(query('has_changes src/x /tmp/other-root')).to.include('cd /tmp/other-root');
249
+ expect(query('ENGINE_ROOT=/inherited-root; has_changes src/y')).to.include('cd /inherited-root');
250
+ expect(query('has_changes src/z')).to.include('cd /home/dd/engine');
251
+ });
252
+
253
+ it('asks the engine for the status of the path it was given', () => {
254
+ expect(query('has_changes src/client/public/cyberia /engine')).to.include(
255
+ 'node bin cmt src/client/public/cyberia --has-changes',
256
+ );
257
+ });
258
+ });
259
+
260
+ describe('prepare_host brings a node up in an order it can recover from', () => {
261
+ const emitted = steps();
262
+ const titles = emitted.map((line) => line.split(' :: ')[0]);
263
+ const step = (title) => emitted[titles.indexOf(title)] || '';
264
+
265
+ it('installs dependencies before running anything from the checkout', () => {
266
+ // Regression: the pull runs through this checkout's own CLI, so a tree whose node_modules
267
+ // no longer match its package.json failed to import — and the step that would have replaced
268
+ // the source never ran. Only the first install is load-bearing; a node reinstalled after the
269
+ // pull as well is fine.
270
+ expect(titles[0]).to.equal('Install dependencies');
271
+ expect(emitted[0]).to.include('npm install');
272
+ expect(titles.indexOf('Pull repository')).to.be.greaterThan(0);
273
+ });
274
+
275
+ it('relinks the checkout CLI after every dependency install', () => {
276
+ const installs = titles.reduce((indexes, title, index) => {
277
+ if (title.startsWith('Install dependencies')) indexes.push(index);
278
+ return indexes;
279
+ }, []);
280
+
281
+ expect(installs).to.have.lengthOf(2);
282
+ for (const index of installs) {
283
+ expect(titles[index + 1]).to.equal('Link underpost CLI');
284
+ expect(emitted[index + 1]).to.include('npm link --force');
285
+ expect(emitted[index + 1]).to.include('command -v underpost');
286
+ expect(emitted[index + 1]).to.include('readlink -f ./bin/index.js');
287
+ }
288
+ });
289
+
290
+ it('replaces the checkout through the engine CLI, with both repositories named', () => {
291
+ expect(step('Pull repository')).to.include('node bin run pull owner/engine');
292
+ expect(step('Pull repository')).to.include('--repo-engine-private owner/engine-private');
293
+ });
294
+
295
+ it('loads the host config last, through the one entry point for that store', () => {
296
+ expect(titles.at(-1)).to.equal('Load host config');
297
+ expect(emitted.at(-1)).to.include('node bin host load');
298
+ });
299
+ });
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ import { expect } from 'chai';
4
+ import { shellExec } from '../../src/server/runtime/process.js';
5
+
6
+ describe('shell command child environment', () => {
7
+ it('passes an isolated environment value without adding it to command text', () => {
8
+ const secret = 'child-only-secret';
9
+ const output = shellExec('printf %s "$UNDERPOST_CHILD_ENV_FIXTURE"', {
10
+ stdout: true,
11
+ silent: true,
12
+ disableLog: true,
13
+ env: { ...process.env, UNDERPOST_CHILD_ENV_FIXTURE: secret },
14
+ });
15
+
16
+ expect(output).to.equal(secret);
17
+ });
18
+ });
@@ -0,0 +1,78 @@
1
+ 'use strict';
2
+
3
+ import { expect } from 'chai';
4
+ import fs from 'fs-extra';
5
+ // Named import: js-yaml's ESM build exports no default.
6
+ import { load } from 'js-yaml';
7
+ import { globSync } from 'node:fs';
8
+ import Underpost from '../../src/index.js';
9
+
10
+ const wrapped = (body) => `ci(package-pwa-microservices-template-ghpkg): ⚙️ ${body}`;
11
+
12
+ const workflows = () =>
13
+ globSync('.github/workflows/*.yml').map((file) => ({
14
+ file,
15
+ source: fs.readFileSync(file, 'utf8'),
16
+ document: load(fs.readFileSync(file, 'utf8')),
17
+ }));
18
+
19
+ const runScripts = (document) =>
20
+ Object.values(document?.jobs ?? {}).flatMap((job) => (job.steps ?? []).map((step) => step.run).filter(Boolean));
21
+
22
+ describe('propagation message', () => {
23
+ describe('resolvePropagationMessage', () => {
24
+ it('keeps every entry of a payload a previous hop committed', () => {
25
+ // The regression this guards: each hop commits the payload through `cmt`, which puts the
26
+ // newest entry on the subject line after the type prefix. Dropping the subject line — the
27
+ // obvious way to strip the prefix — silently propagated only the older entries onward.
28
+ const resolved = Underpost.repo.resolvePropagationMessage(
29
+ wrapped(
30
+ '[cli-repository] Add fastForwardEnginePair method\n[test] Fix coverall\n[package] Remove clean script',
31
+ ),
32
+ );
33
+ expect(resolved.split('\n')).to.deep.equal([
34
+ '[cli-repository] Add fastForwardEnginePair method',
35
+ '[test] Fix coverall',
36
+ '[package] Remove clean script',
37
+ ]);
38
+ });
39
+
40
+ it('carries characters a shell would have eaten', () => {
41
+ const resolved = Underpost.repo.resolvePropagationMessage(wrapped('[cli] Add $HOME lookup\n[test] Fix "quoted"'));
42
+ expect(resolved).to.equal('[cli] Add $HOME lookup\n[test] Fix "quoted"');
43
+ });
44
+
45
+ it('leaves an unwrapped payload alone and drops blank lines', () => {
46
+ expect(Underpost.repo.resolvePropagationMessage('[a] one\n\n [b] two ')).to.equal('[a] one\n[b] two');
47
+ });
48
+
49
+ it('reports nothing to propagate for an empty payload', () => {
50
+ expect(Underpost.repo.resolvePropagationMessage('')).to.equal('');
51
+ expect(Underpost.repo.resolvePropagationMessage(undefined)).to.equal('');
52
+ expect(Underpost.repo.resolvePropagationMessage(wrapped(''))).to.equal('');
53
+ });
54
+ });
55
+
56
+ describe('workflow chain', () => {
57
+ it('never expands a propagated message inside a run script', () => {
58
+ // `${{ }}` is substituted into the script before the shell parses it, so a multi-line
59
+ // payload holding `$` is corrupted and one holding `$(...)` executes. Every hop has to
60
+ // read it from the environment instead.
61
+ const offences = [];
62
+ for (const { file, document } of workflows())
63
+ for (const script of runScripts(document))
64
+ if (/\$\{\{[^}]*\.message[^}]*\}\}/.test(script)) offences.push(`${file}: message expanded in a run script`);
65
+ expect(offences, offences.join('\n')).to.deep.equal([]);
66
+ });
67
+
68
+ it('resolves every propagated commit message through the CLI', () => {
69
+ // One resolver for the whole chain: a workflow that rebuilds the payload with its own shell
70
+ // parsing is how the entries drifted apart between repositories.
71
+ const offences = [];
72
+ for (const { file, source } of workflows())
73
+ if (source.includes('LAST_COMMIT_MESSAGE=') && !source.includes('cmt --propagate-msg'))
74
+ offences.push(`${file}: builds a commit message without \`cmt --propagate-msg\``);
75
+ expect(offences, offences.join('\n')).to.deep.equal([]);
76
+ });
77
+ });
78
+ });
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ import { expect } from 'chai';
4
+ import { redeployPlanFactory } from '../../src/server/runtime/conf.js';
5
+
6
+ describe('a redeploy does not require the inactive colour to exist', () => {
7
+ it('restarts the target colour when it is already deployed', () => {
8
+ expect(redeployPlanFactory({ liveTraffic: 'blue', hasDeployment: (colour) => colour === 'green' })).to.deep.equal({
9
+ targetTraffic: 'green',
10
+ create: false,
11
+ });
12
+ });
13
+
14
+ it('creates the target colour when it was cleaned up by the previous cycle', () => {
15
+ expect(redeployPlanFactory({ liveTraffic: 'green', hasDeployment: (colour) => colour === 'green' })).to.deep.equal({
16
+ targetTraffic: 'blue',
17
+ create: true,
18
+ });
19
+ });
20
+
21
+ it('starts on blue and creates it when nothing is routed yet', () => {
22
+ expect(redeployPlanFactory({})).to.deep.equal({ targetTraffic: 'blue', create: true });
23
+ });
24
+ });