@underpostnet/cyberia 3.2.90 → 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 (490) hide show
  1. package/.dockerignore +1 -0
  2. package/.env.example +16 -0
  3. package/.github/workflows/coverall.cyberia.ci.yml +107 -0
  4. package/.github/workflows/cyberia-client.cd.yml +6 -18
  5. package/.github/workflows/cyberia-server.cd.yml +6 -18
  6. package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
  7. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
  8. package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
  9. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
  10. package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
  11. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
  12. package/.github/workflows/engine-cyberia.cd.yml +6 -78
  13. package/.github/workflows/engine-cyberia.ci.yml +4 -5
  14. package/.github/workflows/ghpkg.ci.yml +42 -21
  15. package/.github/workflows/hardhat.ci.yml +12 -11
  16. package/.github/workflows/npmpkg.ci.yml +17 -15
  17. package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -16
  18. package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
  19. package/.github/workflows/release.cd.yml +2 -9
  20. package/.prettierignore +1 -0
  21. package/AGENTS.md +47 -0
  22. package/CHANGELOG.md +581 -2417
  23. package/CLI-HELP.md +416 -127
  24. package/Dockerfile +25 -9
  25. package/Dockerfile.dev +25 -9
  26. package/Dockerfile.test +4 -4
  27. package/README.md +21 -1
  28. package/bin/build.js +70 -43
  29. package/bin/build.template.js +8 -3
  30. package/bin/cyberia.js +372 -135
  31. package/bin/deploy.js +18 -104
  32. package/bin/index.js +372 -135
  33. package/compose.env +16 -0
  34. package/conf.js +93 -4
  35. package/deploy/cyberia-client/deploy.sh +47 -0
  36. package/deploy/cyberia-client/package.sh +18 -0
  37. package/deploy/cyberia-client/state.sh +14 -0
  38. package/deploy/cyberia-server/deploy.sh +47 -0
  39. package/deploy/cyberia-server/package.sh +18 -0
  40. package/deploy/cyberia-server/state.sh +14 -0
  41. package/deploy/dd-cyberia/deploy.sh +22 -0
  42. package/deploy/dd-cyberia/init.sh +55 -0
  43. package/deploy/dd-cyberia/package.sh +17 -0
  44. package/deploy/dd-cyberia/state.sh +14 -0
  45. package/deploy/dd-cyberia/sync-deploy.sh +116 -0
  46. package/deploy/lib/github-actions-logging.sh +594 -0
  47. package/deploy/lib/host.sh +185 -0
  48. package/deploy/lib/state.sh +62 -0
  49. package/deploy/pwa-microservices-template/deploy.sh +45 -0
  50. package/deploy/release/deploy.sh +32 -0
  51. package/deployment.yaml +7 -2
  52. package/docker-compose.yml +31 -37
  53. package/examples/static-page/README.md +19 -19
  54. package/examples/static-page/ssr-components/CustomPage.js +2 -2
  55. package/hardhat/hardhat.config.js +1 -6
  56. package/hardhat/package-lock.json +104 -43
  57. package/hardhat/package.json +3 -3
  58. package/manifests/alertmanager/deployment.yaml +81 -0
  59. package/manifests/blackbox-exporter/deployment.yaml +75 -0
  60. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +36 -7
  61. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +77 -0
  62. package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
  63. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  64. package/manifests/grafana/deployment.yaml +26 -7
  65. package/manifests/grafana/kustomization.yaml +1 -0
  66. package/manifests/grafana/service.yaml +6 -1
  67. package/manifests/mariadb/pv.yaml +1 -0
  68. package/manifests/mongodb/statefulset.yaml +9 -2
  69. package/manifests/mysql/pv-pvc.yaml +14 -1
  70. package/manifests/postgresql/pv.yaml +12 -1
  71. package/manifests/postgresql/pvc.yaml +1 -0
  72. package/manifests/prometheus/deployment.yaml +18 -22
  73. package/package.json +83 -10
  74. package/scripts/audit-selinux.sh +64 -0
  75. package/scripts/event-monitor.sh +56 -0
  76. package/scripts/gpu-diag.sh +0 -0
  77. package/scripts/ip-info.sh +0 -0
  78. package/scripts/k3s-node-setup.sh +30 -14
  79. package/scripts/kubeadm-node-setup.sh +40 -31
  80. package/scripts/lxd-vm-setup.sh +0 -0
  81. package/scripts/maas-nat-firewalld.sh +0 -0
  82. package/scripts/maas-setup.sh +8 -8
  83. package/scripts/nat-iptables.sh +2 -0
  84. package/scripts/rhel-grpc-setup.sh +0 -0
  85. package/scripts/rocky-kickstart.sh +25 -9
  86. package/scripts/selinux-normalize.sh +907 -0
  87. package/scripts/shutdown-machine.sh +843 -0
  88. package/scripts/test-monitor.sh +3 -3
  89. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +1 -1
  90. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +2 -2
  91. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +2 -2
  92. package/src/api/core/core.controller.js +1 -1
  93. package/src/api/core/core.router.js +2 -2
  94. package/src/api/core/core.service.js +2 -2
  95. package/src/api/crypto/crypto.controller.js +1 -1
  96. package/src/api/crypto/crypto.service.js +1 -1
  97. package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
  98. package/src/api/cyberia-action/cyberia-action.router.js +1 -1
  99. package/src/api/cyberia-action/cyberia-action.service.js +2 -2
  100. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -1
  101. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +1 -1
  102. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +2 -2
  103. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
  104. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
  105. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
  106. package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
  107. package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
  108. package/src/api/cyberia-entity/cyberia-entity.service.js +2 -2
  109. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +1 -1
  110. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +1 -1
  111. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +2 -2
  112. package/src/api/cyberia-instance/cyberia-fallback-capture.js +466 -0
  113. package/src/api/cyberia-instance/cyberia-fallback-default-items.js +63 -0
  114. package/src/api/cyberia-instance/cyberia-fallback-world.js +16 -1
  115. package/src/api/cyberia-instance/cyberia-instance-map.service.js +1 -1
  116. package/src/api/cyberia-instance/cyberia-instance.controller.js +4 -1
  117. package/src/api/cyberia-instance/cyberia-instance.router.js +15 -2
  118. package/src/api/cyberia-instance/cyberia-instance.service.js +45 -2
  119. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
  120. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +1 -0
  121. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
  122. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +2 -2
  123. package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
  124. package/src/api/cyberia-map/cyberia-map.router.js +1 -1
  125. package/src/api/cyberia-map/cyberia-map.service.js +2 -2
  126. package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
  127. package/src/api/cyberia-quest/cyberia-quest.router.js +1 -1
  128. package/src/api/cyberia-quest/cyberia-quest.service.js +2 -2
  129. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
  130. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
  131. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
  132. package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
  133. package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
  134. package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
  135. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +16 -29
  136. package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
  137. package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
  138. package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
  139. package/src/api/default/default.controller.js +1 -1
  140. package/src/api/default/default.router.js +1 -1
  141. package/src/api/default/default.service.js +2 -2
  142. package/src/api/document/document.controller.js +1 -1
  143. package/src/api/document/document.router.js +1 -1
  144. package/src/api/document/document.service.js +2 -2
  145. package/src/api/file/file.controller.js +1 -1
  146. package/src/api/file/file.router.js +1 -1
  147. package/src/api/file/file.service.js +2 -2
  148. package/src/api/instance/instance.controller.js +1 -1
  149. package/src/api/instance/instance.router.js +1 -1
  150. package/src/api/instance/instance.service.js +2 -2
  151. package/src/api/ipfs/ipfs.controller.js +1 -1
  152. package/src/api/ipfs/ipfs.router.js +2 -2
  153. package/src/api/ipfs/ipfs.service.js +2 -2
  154. package/src/api/object-layer/object-layer.controller.js +1 -1
  155. package/src/api/object-layer/object-layer.model.js +204 -3
  156. package/src/api/object-layer/object-layer.router.js +2 -2
  157. package/src/api/object-layer/object-layer.service.js +4 -17
  158. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
  159. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
  160. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
  161. package/src/api/test/test.controller.js +1 -1
  162. package/src/api/test/test.service.js +1 -1
  163. package/src/api/user/guest.service.js +3 -3
  164. package/src/api/user/user.controller.js +1 -1
  165. package/src/api/user/user.router.js +2 -2
  166. package/src/api/user/user.service.js +4 -4
  167. package/src/api.js +5 -9
  168. package/src/cli/app.js +391 -0
  169. package/src/cli/baremetal.js +30 -36
  170. package/src/cli/client.js +306 -0
  171. package/src/cli/cloud-init.js +3 -3
  172. package/src/cli/cluster.js +242 -135
  173. package/src/cli/db.js +126 -67
  174. package/src/cli/deploy.js +158 -60
  175. package/src/cli/docker-compose.js +5 -5
  176. package/src/cli/domains.js +184 -0
  177. package/src/cli/dotenv-store.js +143 -0
  178. package/src/cli/event.js +2281 -0
  179. package/src/cli/fs.js +3 -3
  180. package/src/cli/host.js +672 -0
  181. package/src/cli/image.js +4 -7
  182. package/src/cli/index.js +426 -134
  183. package/src/cli/ipfs.js +34 -30
  184. package/src/cli/kickstart.js +1 -1
  185. package/src/cli/kubectl.js +218 -41
  186. package/src/cli/lxd.js +3 -3
  187. package/src/cli/monitor.js +1359 -26
  188. package/src/cli/package.js +90 -0
  189. package/src/cli/release.js +73 -34
  190. package/src/cli/repository.js +564 -367
  191. package/src/cli/run.js +362 -654
  192. package/src/cli/secrets.js +2158 -964
  193. package/src/cli/ssh.js +651 -331
  194. package/src/cli/state.js +394 -0
  195. package/src/cli/static.js +2 -2
  196. package/src/cli/system.js +26 -13
  197. package/src/cli/test.js +199 -125
  198. package/src/cli/vultr.js +623 -0
  199. package/src/cli/wireguard.js +2930 -0
  200. package/src/client/components/core/CalendarCore.js +53 -96
  201. package/src/client/components/core/Docs.js +258 -211
  202. package/src/client/components/core/FileExplorer.js +0 -21
  203. package/src/client/components/core/PanelForm.js +4 -4
  204. package/src/client/components/core/Repository.js +56 -0
  205. package/src/client/components/core/Translate.js +7 -0
  206. package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
  207. package/src/client/components/core/Wallet.js +0 -11
  208. package/src/client/components/core/Worker.js +7 -1
  209. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
  210. package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +368 -0
  211. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +35 -1
  212. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +4 -0
  213. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
  214. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
  215. package/src/client/components/default/AppShellDefault.js +1 -1
  216. package/src/client/components/default/SettingsDefault.js +2 -2
  217. package/src/client/components/itemledger/SettingsItemledger.js +2 -2
  218. package/src/client/components/underpost/AppShellUnderpost.js +3 -2
  219. package/src/client/components/underpost/SettingsUnderpost.js +2 -2
  220. package/src/client/public/cyberia-docs/ARCHITECTURE.md +17 -3
  221. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +32 -5
  222. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +1 -1
  223. package/src/client/public/cyberia-docs/CYBERIA.md +21 -1
  224. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
  225. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  226. package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
  227. package/src/client/public/default/android-chrome-144x144.png +0 -0
  228. package/src/client/public/default/android-chrome-192x192.png +0 -0
  229. package/src/client/public/default/android-chrome-256x256.png +0 -0
  230. package/src/client/public/default/android-chrome-36x36.png +0 -0
  231. package/src/client/public/default/android-chrome-384x384.png +0 -0
  232. package/src/client/public/default/android-chrome-48x48.png +0 -0
  233. package/src/client/public/default/android-chrome-512x512.png +0 -0
  234. package/src/client/public/default/android-chrome-72x72.png +0 -0
  235. package/src/client/public/default/android-chrome-96x96.png +0 -0
  236. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  237. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  238. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  239. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  240. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  241. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  242. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  243. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  244. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  245. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  246. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  247. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  248. package/src/client/public/default/apple-touch-icon.png +0 -0
  249. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  250. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  251. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  252. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  253. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  254. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  255. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  256. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  257. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  258. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  259. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  260. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  261. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  262. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  263. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  264. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  265. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  266. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  267. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  268. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  269. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  270. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  271. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  272. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  273. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  274. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  275. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  276. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  277. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  278. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  279. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  280. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  281. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  282. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  283. package/src/client/public/default/assets/background/white.jpg +0 -0
  284. package/src/client/public/default/browserconfig.xml +1 -1
  285. package/src/client/public/default/favicon-16x16.png +0 -0
  286. package/src/client/public/default/favicon-32x32.png +0 -0
  287. package/src/client/public/default/favicon-48x48.png +0 -0
  288. package/src/client/public/default/favicon.ico +0 -0
  289. package/src/client/public/default/manifest.webmanifest +5 -5
  290. package/src/client/public/default/mstile-144x144.png +0 -0
  291. package/src/client/public/default/mstile-150x150.png +0 -0
  292. package/src/client/public/default/mstile-310x150.png +0 -0
  293. package/src/client/public/default/mstile-310x310.png +0 -0
  294. package/src/client/public/default/mstile-70x70.png +0 -0
  295. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  296. package/src/client/public/default/yandex-browser-manifest.json +1 -1
  297. package/src/client/services/cyberia-instance/cyberia-instance.service.js +40 -0
  298. package/src/client/services/object-layer/object-layer.management.js +4 -4
  299. package/src/client/ssr/RootDocument.js +1 -1
  300. package/src/client/ssr/body/404.js +1 -1
  301. package/src/client/ssr/body/500.js +1 -1
  302. package/src/client/ssr/body/CacheControl.js +1 -1
  303. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
  304. package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
  305. package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
  306. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
  307. package/src/client/ssr/head/CryptokoynScripts.js +1 -1
  308. package/src/client/ssr/head/Css.js +1 -1
  309. package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
  310. package/src/client/ssr/head/DefaultScripts.js +1 -1
  311. package/src/client/ssr/head/ItemledgerScripts.js +1 -1
  312. package/src/client/ssr/head/Microdata.js +1 -1
  313. package/src/client/ssr/head/Production.js +1 -1
  314. package/src/client/ssr/head/Pwa.js +1 -1
  315. package/src/client/ssr/head/PwaItemledger.js +1 -1
  316. package/src/client/ssr/head/Seo.js +1 -1
  317. package/src/client/ssr/head/UnderpostScripts.js +1 -1
  318. package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
  319. package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
  320. package/src/client/ssr/views/Cyberia404.js +7 -5
  321. package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
  322. package/src/client/ssr/views/Maintenance.js +1 -1
  323. package/src/client/ssr/views/NoNetworkConnection.js +1 -1
  324. package/src/client/ssr/views/Test.js +1 -1
  325. package/src/client/sw/core.sw.js +20 -14
  326. package/src/client-builder/client-build-docs.js +61 -46
  327. package/src/client-builder/client-build-live.js +2 -2
  328. package/src/client-builder/client-build.js +58 -44
  329. package/src/client-builder/client-dev-server.js +3 -3
  330. package/src/client-builder/client-icons.js +2 -2
  331. package/src/client-builder/ssr.js +3 -3
  332. package/src/client.build.js +3 -6
  333. package/src/client.dev.js +3 -6
  334. package/src/db/DataBaseProvider.js +186 -3
  335. package/src/db/mariadb/MariaDB.js +3 -2
  336. package/src/db/mongo/MongoBootstrap.js +273 -101
  337. package/src/db/mongo/MongooseDB.js +11 -8
  338. package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
  339. package/src/grpc/cyberia/grpc-server.js +1 -1
  340. package/src/index.js +103 -23
  341. package/src/mailer/EmailRender.js +2 -2
  342. package/src/mailer/MailerInterceptor.js +87 -0
  343. package/src/mailer/MailerProvider.js +50 -6
  344. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +1 -1
  345. package/src/projects/cyberia/besu-genesis-generator.js +3 -3
  346. package/src/projects/cyberia/catalog-cyberia.js +54 -6
  347. package/src/projects/cyberia/gemini-client.js +1 -1
  348. package/src/projects/cyberia/generate-saga.js +15 -24
  349. package/src/projects/cyberia/hot-reload-trigger.js +1 -1
  350. package/src/projects/cyberia/instance-data.js +22 -3
  351. package/src/projects/cyberia/ipfs-client.js +4 -4
  352. package/src/projects/cyberia/map-preview-generator.js +1 -1
  353. package/src/projects/cyberia/object-layer.js +12 -22
  354. package/src/projects/cyberia/semantic-layer-generator.js +1 -1
  355. package/src/projects/underpost/catalog-underpost.js +13 -2
  356. package/src/proxy.js +4 -7
  357. package/src/runtime/cyberia-client/Dockerfile +9 -4
  358. package/src/runtime/cyberia-client/Dockerfile.dev +8 -2
  359. package/src/runtime/cyberia-server/Dockerfile +9 -4
  360. package/src/runtime/cyberia-server/Dockerfile.dev +8 -2
  361. package/src/runtime/engine-cyberia/Dockerfile +25 -9
  362. package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
  363. package/src/runtime/engine-cyberia/Dockerfile.test +4 -4
  364. package/src/runtime/engine-cyberia/compose.env +16 -0
  365. package/src/runtime/engine-cyberia/docker-compose.yml +31 -37
  366. package/src/runtime/express/Express.js +32 -27
  367. package/src/runtime/lampp/Lampp.js +22 -70
  368. package/src/runtime/nginx/Nginx.js +1 -1
  369. package/src/runtime/wp/Wp.js +16 -48
  370. package/src/server/{catalog.js → build/catalog.js} +15 -5
  371. package/src/server/build/coverage.js +117 -0
  372. package/src/server/build/execution.js +402 -0
  373. package/src/server/build/package.js +465 -0
  374. package/src/server/build/testing.js +528 -0
  375. package/src/server/{dns.js → network/dns.js} +241 -14
  376. package/src/server/network/forward-proxy.js +541 -0
  377. package/src/server/{middlewares.js → network/middlewares.js} +59 -4
  378. package/src/server/network/node-capability.js +98 -0
  379. package/src/server/{peer.js → network/peer.js} +3 -3
  380. package/src/server/{proxy.js → network/proxy.js} +7 -13
  381. package/src/server/network/router.js +356 -0
  382. package/src/server/{tls.js → network/tls.js} +2 -2
  383. package/src/server/network/underpost-compression.js +186 -0
  384. package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +26 -16
  385. package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +19 -3
  386. package/src/server/{cri.js → ops/cri.js} +2 -2
  387. package/src/server/ops/cron.js +949 -0
  388. package/src/server/ops/event-notification.js +284 -0
  389. package/src/server/{logger.js → ops/logger.js} +108 -23
  390. package/src/server/ops/monitoring.js +1724 -0
  391. package/src/server/ops/systemd.js +259 -0
  392. package/src/server/{conf.js → runtime/conf.js} +521 -520
  393. package/src/server/runtime/config-scope.js +215 -0
  394. package/src/server/runtime/environment.js +149 -0
  395. package/src/server/{process.js → runtime/process.js} +153 -13
  396. package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
  397. package/src/server/{runtime.js → runtime/runtime.js} +12 -8
  398. package/src/server/{start.js → runtime/start.js} +128 -39
  399. package/src/server/{auth.js → security/auth.js} +7 -8
  400. package/src/server/security/container-storage.js +382 -0
  401. package/src/server/{crypto.js → security/crypto.js} +1 -1
  402. package/src/server/security/selinux.js +185 -0
  403. package/src/server/{backup.js → storage/backup.js} +17 -8
  404. package/src/server/{data-query.js → storage/data-query.js} +1 -1
  405. package/src/server/{downloader.js → storage/downloader.js} +2 -2
  406. package/src/server/storage/repository.js +68 -0
  407. package/src/server.js +4 -7
  408. package/src/ws/IoInterface.js +1 -1
  409. package/src/ws/IoServer.js +1 -1
  410. package/src/ws/core/core.ws.connection.js +1 -1
  411. package/src/ws/core/core.ws.emit.js +1 -1
  412. package/src/ws/core/core.ws.server.js +1 -1
  413. package/src/ws/default/default.ws.connection.js +1 -1
  414. package/src/ws/default/default.ws.emit.js +1 -1
  415. package/src/ws/default/default.ws.server.js +1 -1
  416. package/test/e2e/event-e2e-public-ingress-down.js +45 -0
  417. package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
  418. package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
  419. package/test/{api.test.js → integration/app/api.test.js} +33 -14
  420. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +30 -0
  421. package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +2 -1
  422. package/test/integration/app/cyberia/cyberia-load.test.js +467 -0
  423. package/test/integration/app/cyberia/fallback-world-capture.test.js +253 -0
  424. package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
  425. package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
  426. package/test/integration/infra/1-security/config-scope.test.js +305 -0
  427. package/test/integration/infra/1-security/container-storage.test.js +356 -0
  428. package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
  429. package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
  430. package/test/integration/infra/1-security/selinux.test.js +69 -0
  431. package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
  432. package/test/integration/infra/1-security/systemd-service.test.js +70 -0
  433. package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
  434. package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
  435. package/test/integration/infra/2-network/node-capability.test.js +182 -0
  436. package/test/integration/infra/2-network/wireguard-cli.test.js +1163 -0
  437. package/test/integration/infra/2-network/wireguard-edge.test.js +1731 -0
  438. package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
  439. package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
  440. package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
  441. package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
  442. package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
  443. package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
  444. package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +47 -6
  445. package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +56 -4
  446. package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
  447. package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
  448. package/test/integration/infra/5-observability/event-notification.test.js +197 -0
  449. package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
  450. package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
  451. package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
  452. package/test/support/shell-harness.js +73 -0
  453. package/test/unit/build-template.test.js +97 -0
  454. package/test/unit/build-workflow-offline.test.js +132 -0
  455. package/test/unit/catalog.test.js +71 -0
  456. package/test/unit/client-build-docs.test.js +334 -0
  457. package/test/unit/conf-loading.test.js +303 -0
  458. package/test/unit/conf-resolution.test.js +979 -0
  459. package/test/unit/coverage-artifact.test.js +130 -0
  460. package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
  461. package/test/unit/deploy-env-resolution.test.js +38 -0
  462. package/test/unit/deploy-log-table.test.js +447 -0
  463. package/test/unit/execution-profiles.test.js +219 -0
  464. package/test/unit/fleet-sync-source.test.js +149 -0
  465. package/test/unit/logger-redaction.test.js +112 -0
  466. package/test/unit/package.test.js +403 -0
  467. package/test/unit/prepare-host.test.js +299 -0
  468. package/test/unit/process-environment.test.js +18 -0
  469. package/test/unit/propagation-message.test.js +78 -0
  470. package/test/unit/redeploy-plan.test.js +24 -0
  471. package/test/unit/release-bump.test.js +474 -0
  472. package/test/unit/ssh-output-redaction.test.js +28 -0
  473. package/test/unit/start-options.test.js +46 -0
  474. package/test/unit/test-tiers.test.js +193 -0
  475. package/vitest.config.js +58 -0
  476. package/.nycrc +0 -9
  477. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
  478. package/manifests/mongodb/pv-pvc.yaml +0 -59
  479. package/scripts/link-local-underpost-cli.sh +0 -6
  480. package/src/api/user/user.build.js +0 -16
  481. package/src/cli/env.js +0 -177
  482. package/src/client/components/core/Blockchain.js +0 -41
  483. package/src/client/components/core/Blog.js +0 -9
  484. package/src/client/components/core/KeyboardAvoidance.js +0 -145
  485. package/src/client/public/default/assets/background/dark.jpg +0 -0
  486. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  487. package/src/client/public/default/assets/background/white0.jpg +0 -0
  488. package/src/client/public/doc/favicon.ico +0 -0
  489. package/src/client/public/doc/sitemap +0 -148
  490. package/src/server/cron.js +0 -476
@@ -0,0 +1,594 @@
1
+ # Logging helpers for deploy/<deploy-id>/*.sh. Sourced, never executed directly.
2
+ #
3
+ # Deploy script contract:
4
+ # - deploy_start once for the run's title, prepare_host from lib/host.sh next,
5
+ # then one deploy_step call per remote command, each with its own label
6
+ # - the body lives in main(), invoked on the last line: the first remote command
7
+ # pulls this repository, rewriting the running script while bash reads it
8
+ #
9
+ # deploy_step is the entry point every deploy script uses. run_quiet stays the
10
+ # mechanism underneath it, for the rare caller that needs a different report
11
+ # pattern or passthrough window.
12
+ #
13
+ # run_quiet hides normal output and returns the command's exit status so
14
+ # `set -e` stops the deployment. Lines matching `patterns` that parse as a
15
+ # deployment pod report are folded into a table — one row per pod, three columns
16
+ # wide — instead of being streamed; the monitor's raw `deploy-monitor` JSON emits
17
+ # are consumed into that table's cells rather than printed. The monitor
18
+ # iteration and its clock are per frame, not per pod, so they title the table
19
+ # rather than repeating down a column of every row. Anything else within
20
+ # `lines_after` lines of a match scrolls above the table. On failure it keeps
21
+ # two temp files and prints their paths in red instead of their contents: the
22
+ # error trace and the full unfiltered log up to the error. The trace is stderr
23
+ # plus the failing tail of the merged log, because the engine CLI reports through
24
+ # its logger and that writes to stdout — stderr alone routinely holds nothing but
25
+ # git progress output.
26
+ #
27
+ # The table renders three ways, because a log viewer is not a terminal:
28
+ # - terminal: redrawn in place, cursor relative, one frame at a time
29
+ # - CI (GITHUB_ACTIONS/RUN_QUIET_CI): no cursor addressing exists there, so the
30
+ # changed rows stream inside a collapsed `::group::` and the final table is
31
+ # printed after it, expanded
32
+ # - anywhere else: changed rows appended
33
+ # Colour is ANSI SGR only and is emitted in all three (GitHub renders SGR in
34
+ # step logs); NO_COLOR or RUN_QUIET_PLAIN turns it off.
35
+
36
+ if [ -n "${NO_COLOR:-}${RUN_QUIET_PLAIN:-}" ]; then
37
+ RUN_QUIET_RED=''
38
+ RUN_QUIET_RESET=''
39
+ else
40
+ RUN_QUIET_RED=$'\033[0;31m'
41
+ RUN_QUIET_RESET=$'\033[0m'
42
+ fi
43
+
44
+ RUN_QUIET_NODE_NAME=$(hostname 2>/dev/null | tr '[:upper:]' '[:lower:]')
45
+ RUN_QUIET_NODE_TAG=${RUN_QUIET_NODE_NAME:+ [$RUN_QUIET_NODE_NAME]}
46
+
47
+ # The report pattern and the passthrough window describe the deployment log
48
+ # format, not any one step, so they are declared once here instead of being
49
+ # repeated at every call site.
50
+ DEPLOY_REPORT_PATTERN='Target pod:'
51
+ DEPLOY_REPORT_LINES_AFTER=14
52
+
53
+ # Titles a deploy run, in the same shape as the step lines below it.
54
+ deploy_start() {
55
+ echo "$RUN_QUIET_NODE_TAG $(date -Is) ▶▶ $1"
56
+ }
57
+
58
+ # One deploy step: a label and the command that carries it.
59
+ deploy_step() {
60
+ local label="$1"
61
+ shift
62
+
63
+ run_quiet "$label" "$DEPLOY_REPORT_PATTERN" "$DEPLOY_REPORT_LINES_AFTER" "$@"
64
+ }
65
+
66
+ run_quiet() {
67
+ local label="$1"
68
+ local patterns="$2"
69
+ local lines_after="$3"
70
+ shift 3
71
+
72
+ local debug_log
73
+ local error_log
74
+ local fail_flag
75
+ local fatal
76
+ local reason
77
+ local fifo_dir
78
+ local filter_pid
79
+ local stderr_pid
80
+ local color=0
81
+ local groups=0
82
+ local redraw=0
83
+ local width=0
84
+ local rows=0
85
+ local status=0
86
+
87
+ echo "$RUN_QUIET_NODE_TAG $(date -Is) ▶ $label"
88
+
89
+ [ -n "${NO_COLOR:-}${RUN_QUIET_PLAIN:-}" ] || color=1
90
+
91
+ if [ -t 1 ] && [ "${TERM:-dumb}" != dumb ] && [ -z "${RUN_QUIET_PLAIN:-}" ]; then
92
+ redraw=1
93
+ width=${COLUMNS:-0}
94
+ [ "$width" -gt 0 ] 2>/dev/null || width=$(tput cols 2>/dev/null || echo 0)
95
+ rows=${LINES:-0}
96
+ [ "$rows" -gt 0 ] 2>/dev/null || rows=$(tput lines 2>/dev/null || echo 0)
97
+ # Without a known width a long row wraps, and the cursor-up count that
98
+ # addresses the table no longer matches the lines it printed.
99
+ [ "$width" -ge 20 ] || redraw=0
100
+ fi
101
+
102
+ if [ "$redraw" -eq 0 ] && [ -z "${RUN_QUIET_PLAIN:-}" ] && [ -n "${GITHUB_ACTIONS:-}${RUN_QUIET_CI:-}" ]; then
103
+ groups=1
104
+ fi
105
+
106
+ debug_log=$(mktemp --suffix=.debug.log)
107
+ error_log=$(mktemp --suffix=.error.log)
108
+ fail_flag=$(mktemp --suffix=.fatal)
109
+ : >"$fail_flag"
110
+ fifo_dir=$(mktemp -d)
111
+ mkfifo "$fifo_dir/merged" "$fifo_dir/stderr"
112
+
113
+ # The filter reads the live stream rather than the finished log: a deployment
114
+ # monitor prints its report for minutes before exiting, so a pass over the
115
+ # completed file would show nothing until then. fflush defeats awk's block
116
+ # buffering, which otherwise withholds output whenever stdout is a pipe.
117
+ # awk writes the debug log itself rather than piping through tee, so the
118
+ # reader stays a single process that a kill can always release.
119
+ #
120
+ # On a terminal the table is the only live region and always sits at the
121
+ # bottom: rows are overwritten one by one (cursor up, then erase to end of
122
+ # line as each row is rewritten) so the section never blanks between frames,
123
+ # and a passthrough line is printed after erasing the table and before
124
+ # drawing it again. All of that is cursor relative, so every row must occupy
125
+ # exactly one terminal line: rows are cut to the terminal width, counting
126
+ # display columns rather than bytes so colour escapes neither inflate the
127
+ # measurement nor get sliced in half. Elsewhere nothing is cut and nothing
128
+ # is overwritten — the frames stream, folded into a CI group when there is
129
+ # one to fold them into.
130
+ awk \
131
+ -v pattern="$patterns" \
132
+ -v lines_after="$lines_after" \
133
+ -v debug_log="$debug_log" \
134
+ -v redraw="$redraw" \
135
+ -v color="$color" \
136
+ -v groups="$groups" \
137
+ -v label="$label" \
138
+ -v width="$width" \
139
+ -v rows="$rows" \
140
+ -v started="$(date +%H:%M:%S)" \
141
+ -v fail_flag="$fail_flag" \
142
+ -v handoff="$RUN_QUIET_NODE_TAG $(date -Is) ▶ Switch traffic" '
143
+ function strip(s) {
144
+ gsub(esc_seq, "", s)
145
+ return s
146
+ }
147
+ function pad(s, w) {
148
+ while (length(s) < w) s = s " "
149
+ return s
150
+ }
151
+ # Pod names differ in their tail, so a name too wide for its column keeps
152
+ # the end rather than the deploy prefix every pod shares.
153
+ function trim(s, w) {
154
+ return length(s) <= w ? s : ".." substr(s, length(s) - w + 3)
155
+ }
156
+ function rule(n, r) {
157
+ r = ""
158
+ while (n-- > 0) r = r "-"
159
+ return r
160
+ }
161
+ function paint(s, sgr) {
162
+ return color ? esc "[" sgr "m" s esc "[0m" : s
163
+ }
164
+ function fit(s, out, visible) {
165
+ if (!redraw) return s
166
+ out = ""
167
+ visible = 0
168
+ while (length(s) > 0) {
169
+ if (match(s, "^" esc_seq)) {
170
+ out = out substr(s, 1, RLENGTH)
171
+ s = substr(s, RLENGTH + 1)
172
+ continue
173
+ }
174
+ if (visible >= width - 1) return out esc "[0m"
175
+ out = out substr(s, 1, 1)
176
+ s = substr(s, 2)
177
+ visible++
178
+ }
179
+ return out
180
+ }
181
+ function put(line) {
182
+ printf "%s%s\n", fit(line), redraw ? esc "[K" : ""
183
+ fflush()
184
+ }
185
+ # GitHub renders no cursor motion, so the live region becomes a
186
+ # collapsed section: every frame streams into it and the settled table
187
+ # is reprinted outside it.
188
+ function open_group() {
189
+ if (!groups || group_open) return
190
+ group_open = 1
191
+ printf "::group::%s monitor frames\n", label
192
+ fflush()
193
+ }
194
+ function close_group() {
195
+ if (!group_open) return
196
+ group_open = 0
197
+ # The next run of rows opens its own section, and a section starts
198
+ # with its title and header.
199
+ appended_header = 0
200
+ appended_cycle = 0
201
+ printf "::endgroup::\n"
202
+ fflush()
203
+ }
204
+ function final_table( i) {
205
+ if (!groups || pod_count == 0) return
206
+ close_group()
207
+ measure()
208
+ title_line()
209
+ header_lines()
210
+ for (i = 1; i <= pod_count; i++) pod_line(pods[i])
211
+ }
212
+ function json_value(key, found) {
213
+ if (!match($0, "\"" key "\"[ ]*:[ ]*\"[^\"]*\"")) return ""
214
+ found = substr($0, RSTART, RLENGTH)
215
+ sub("^\"" key "\"[ ]*:[ ]*\"", "", found)
216
+ sub("\"$", "", found)
217
+ return found
218
+ }
219
+ function apply_event( was_k8s_ready, was_runtime_ready, i) {
220
+ events_seen = 1
221
+ was_k8s_ready = k8s_ready
222
+ was_runtime_ready = runtime_ready
223
+ if (event_phase == "kubernetes") k8s_ready = (event_state == "pod_ready")
224
+ else if (event_phase == "runtime") {
225
+ runtime_ready = (event_state == "runtime_ready")
226
+ if (event_status != "") last_runtime = event_status
227
+ if (is_fatal(event_status)) note_fatal("runtime event", "status=" event_status)
228
+ }
229
+ if (redraw) {
230
+ if (drawn > 0) {
231
+ clear_table()
232
+ draw_table()
233
+ }
234
+ return
235
+ }
236
+ # Readiness reaches the cells through the events alone, so without a
237
+ # live table it is the only thing that can move a row.
238
+ if (was_k8s_ready == k8s_ready && was_runtime_ready == runtime_ready) return
239
+ for (i = 1; i <= pod_count; i++) append_row(pods[i])
240
+ }
241
+ # Both phases confirmed is the monitor signing off; the hand-off waits
242
+ # for the report lines of that iteration so the table lands on its final
243
+ # frame first.
244
+ function ready_pending() {
245
+ return events_seen ? (k8s_ready && runtime_ready) : all_pods_running()
246
+ }
247
+ # One report line per pod: "Target pod: NAME | Pod status: X | Runtime status: Y".
248
+ function read_pod_line(line, plain, cell, pod, k8s, runtime) {
249
+ plain = strip(line)
250
+ if (plain !~ /^Target pod: /) return 0
251
+ if (split(plain, cell, / \| /) < 3) return 0
252
+ pod = cell[1]; sub(/^Target pod:[ ]*/, "", pod)
253
+ k8s = cell[2]; sub(/^Pod status:[ ]*/, "", k8s)
254
+ runtime = cell[3]; sub(/^Runtime status:[ ]*/, "", runtime)
255
+ if (pod == "") return 0
256
+ if (is_fatal(runtime)) note_fatal("pod " pod, "runtime status=" runtime)
257
+ if (!(pod in pod_row)) {
258
+ pod_row[pod] = ++pod_count
259
+ pods[pod_count] = pod
260
+ }
261
+ # The report itself is unstamped: the clock is the one the monitor
262
+ # printed for this iteration, so the title advances with the run.
263
+ cycle_time = last_time != "" ? last_time : started
264
+ pod_k8s[pod] = k8s
265
+ pod_runtime[pod] = runtime
266
+ current_pod = pod
267
+ return 1
268
+ }
269
+ # Every pod reporting its expected runtime status with no pending
270
+ # marker is what the deployment itself calls ready. `error` is
271
+ # the fatal value in the RUNTIME_STATUS contract: a terminal state, not a
272
+ # ready one, and reading it as ready handed off to the traffic switch on
273
+ # a deployment that had already failed.
274
+ function all_pods_running( i, pod, runtime) {
275
+ if (pod_count == 0) return 0
276
+ for (i = 1; i <= pod_count; i++) {
277
+ pod = pods[i]
278
+ if (pod_k8s[pod] != "Running") return 0
279
+ runtime = runtime_cell(pod)
280
+ if (runtime == "" || runtime ~ /pending/ || is_fatal(runtime)) return 0
281
+ }
282
+ return 1
283
+ }
284
+ # The bare contract value, not a substring: a phase name that merely
285
+ # contains it (or a log line quoting it) is not a fatal latch.
286
+ function is_fatal(status) {
287
+ return status == "error"
288
+ }
289
+ # Stack frames and source URLs carry absolute host paths and module layout,
290
+ # which must not reach a CI transcript. Both log files still hold them.
291
+ function is_trace(line) {
292
+ return line ~ /^[ \t]*at [^ ]/ || line ~ /file:\/\/\// || line ~ /^[ \t]*at async / || line ~ /^[A-Za-z_]*Error: /
293
+ }
294
+ # Records the fatal latch for run_quiet. A step can report this and still
295
+ # exit 0 — the in-pod lifecycle deliberately does not crash the container
296
+ # — so the exit status alone cannot be trusted to stop the deployment.
297
+ function note_fatal(source, detail) {
298
+ if (fatal_seen) return
299
+ fatal_seen = 1
300
+ printf "%s: %s\n", source, detail > fail_flag
301
+ close(fail_flag)
302
+ }
303
+ # The table stops being a live region here: the deployment is handing
304
+ # over to the traffic switch, so the last frame stays on screen and the
305
+ # chatter the runner prints below it is dropped.
306
+ function hand_off() {
307
+ handed_off = 1
308
+ remaining = 0
309
+ drawn = 0
310
+ last_pod_line = 0
311
+ final_table()
312
+ put(handoff)
313
+ }
314
+ # A later monitor in the same command (a second colour, a rollback) opens
315
+ # its own table below the one that was handed off.
316
+ function reset_table() {
317
+ close_group()
318
+ handed_off = 0
319
+ events_seen = 0
320
+ k8s_ready = 0
321
+ runtime_ready = 0
322
+ pod_count = 0
323
+ cycles = 0
324
+ cycle_time = ""
325
+ appended_header = 0
326
+ appended_cycle = 0
327
+ drawn = 0
328
+ delete pods
329
+ delete pod_row
330
+ delete pod_k8s
331
+ delete pod_runtime
332
+ delete last_row
333
+ }
334
+ # pod_ready is a deployment-wide event: it only annotates a pod whose
335
+ # own phase already agrees, never a stale one still coming up.
336
+ function k8s_cell(pod, cell) {
337
+ cell = pod_k8s[pod]
338
+ return (k8s_ready && cell == "Running") ? cell " (ready)" : cell
339
+ }
340
+ function runtime_cell(pod) {
341
+ return pod_runtime[pod] != "" ? pod_runtime[pod] : last_runtime
342
+ }
343
+ # Columns only ever grow: a cell that shrinks must not reflow the table
344
+ # under the reader between frames.
345
+ function measure( i, pod, over, budget) {
346
+ for (i = 1; i <= pod_count; i++) {
347
+ pod = pods[i]
348
+ if (length(pod) > w_pod) w_pod = length(pod)
349
+ if (length(k8s_cell(pod)) > w_k8s) w_k8s = length(k8s_cell(pod))
350
+ if (length(runtime_cell(pod)) > w_runtime) w_runtime = length(runtime_cell(pod))
351
+ }
352
+ # 10 columns of borders and padding. On a narrow terminal the pod
353
+ # column gives up room first, then the status columns, before fit()
354
+ # starts cutting cells off the right edge.
355
+ w_pod_fit = w_pod
356
+ w_runtime_fit = w_runtime
357
+ w_k8s_fit = w_k8s
358
+ # A streamed table cannot re-pad the rows it already printed, so the
359
+ # status columns start wide enough for the values the monitor is
360
+ # known to report and stop drifting under the header.
361
+ if (!redraw) {
362
+ if (w_k8s_fit < 17) w_k8s_fit = 17
363
+ if (w_runtime_fit < 28) w_runtime_fit = 28
364
+ return
365
+ }
366
+ # fit() cuts the last column, so the row has to land inside it.
367
+ budget = width - 1
368
+ over = row_width() - budget
369
+ if (over > 0) {
370
+ w_pod_fit = w_pod_fit - over < 12 ? 12 : w_pod_fit - over
371
+ over = row_width() - budget
372
+ }
373
+ if (over > 0) {
374
+ w_runtime_fit = w_runtime_fit - over < 16 ? 16 : w_runtime_fit - over
375
+ over = row_width() - budget
376
+ }
377
+ if (over > 0) w_k8s_fit = w_k8s_fit - over < 12 ? 12 : w_k8s_fit - over
378
+ }
379
+ function row_width() {
380
+ return w_pod_fit + w_k8s_fit + w_runtime_fit + 10
381
+ }
382
+ # The iteration and the clock are one per frame, not one per pod: they
383
+ # title the table instead of repeating down two columns of it.
384
+ function title_line() {
385
+ put(paint(sprintf("%s (refresh #%d, %s)", label, cycles,
386
+ cycle_time != "" ? cycle_time : started), "1"))
387
+ }
388
+ function header_lines() {
389
+ put(paint(sprintf("| %s | %s | %s |", pad("POD NAME", w_pod_fit),
390
+ pad("K8S STATUS", w_k8s_fit), pad("RUNTIME STATUS", w_runtime_fit)), "1"))
391
+ put(paint(sprintf("|%s|%s|%s|", rule(w_pod_fit + 2), rule(w_k8s_fit + 2),
392
+ rule(w_runtime_fit + 2)), "2"))
393
+ }
394
+ function pod_line(pod, runtime) {
395
+ runtime = runtime_cell(pod)
396
+ put(sprintf("| %s | %s | %s |",
397
+ paint(pad(trim(pod, w_pod_fit), w_pod_fit), "1"),
398
+ paint(pad(trim(k8s_cell(pod), w_k8s_fit), w_k8s_fit), k8s_ready ? "32" : "33"),
399
+ paint(pad(trim(runtime, w_runtime_fit), w_runtime_fit), (runtime ~ /pending/ || !runtime_ready) ? "36" : "32")))
400
+ }
401
+ function clear_table() {
402
+ if (!redraw || drawn == 0) return
403
+ printf "%s[%dA%s[J", esc, drawn, esc
404
+ drawn = 0
405
+ }
406
+ function draw_table( i) {
407
+ if (!redraw || pod_count == 0) return
408
+ # A table taller than the screen scrolls, and the cursor-up count no
409
+ # longer addresses the rows it drew; degrade to appended rows.
410
+ if (rows > 0 && pod_count + 3 >= rows) {
411
+ redraw = 0
412
+ drawn = 0
413
+ return
414
+ }
415
+ measure()
416
+ title_line()
417
+ header_lines()
418
+ for (i = 1; i <= pod_count; i++) pod_line(pods[i])
419
+ drawn = pod_count + 3
420
+ }
421
+ # Without a live table a row is only worth printing when its cells
422
+ # actually moved; the iteration count alone is not a change. The title is
423
+ # reprinted whenever a later iteration is the one moving rows, so a
424
+ # streamed row is still dated without carrying its own clock column.
425
+ function append_row(pod, cells) {
426
+ cells = pod "|" k8s_cell(pod) "|" runtime_cell(pod)
427
+ if (cells == last_row[pod]) return
428
+ last_row[pod] = cells
429
+ measure()
430
+ open_group()
431
+ if (appended_cycle != cycles) {
432
+ title_line()
433
+ appended_cycle = cycles
434
+ }
435
+ if (!appended_header) {
436
+ header_lines()
437
+ appended_header = 1
438
+ }
439
+ pod_line(pod)
440
+ }
441
+ BEGIN {
442
+ w_pod = length("POD NAME")
443
+ w_k8s = length("K8S STATUS")
444
+ w_runtime = length("RUNTIME STATUS")
445
+ group_open = 0
446
+ esc = sprintf("%c", 27)
447
+ esc_seq = esc "\\[[0-9;]*[A-Za-z]"
448
+ clock = "[0-9][0-9]:[0-9][0-9]:[0-9][0-9]"
449
+ json_open = "deploy-monitor:[ ]*[{]"
450
+ json_close = "^[ \t]*[}],?[ \t]*$"
451
+ }
452
+ {
453
+ print > debug_log
454
+ # The monitor stamps its own lines in local time; the ISO field
455
+ # inside an emit is UTC, so it never feeds the column.
456
+ if ($0 !~ /"timestamp"/ && match(strip($0), clock)) last_time = substr(strip($0), RSTART, RLENGTH)
457
+ }
458
+ {
459
+ if (!handed_off && $0 !~ pattern && ready_pending()) hand_off()
460
+ if (handed_off) {
461
+ if ($0 !~ pattern) next
462
+ reset_table()
463
+ }
464
+ # The monitor JSON is state already carried by the table cells: it is
465
+ # consumed here and never reaches the terminal.
466
+ if (in_json) {
467
+ if ($0 ~ json_close) {
468
+ in_json = 0
469
+ apply_event()
470
+ } else {
471
+ if (json_value("phase") != "") event_phase = json_value("phase")
472
+ if (json_value("state") != "") event_state = json_value("state")
473
+ if (json_value("status") != "") event_status = json_value("status")
474
+ }
475
+ if (remaining > 0) remaining--
476
+ last_pod_line = 0
477
+ next
478
+ }
479
+ if ($0 ~ json_open) {
480
+ in_json = 1
481
+ event_phase = event_state = event_status = ""
482
+ if (remaining > 0) remaining--
483
+ last_pod_line = 0
484
+ next
485
+ }
486
+ if (read_pod_line($0)) {
487
+ # Pod reports arrive back to back, one per pod, once per monitor
488
+ # iteration: the first of a run opens a new cycle.
489
+ if (!last_pod_line) cycles++
490
+ last_pod_line = 1
491
+ remaining = lines_after + 1
492
+ if (redraw) {
493
+ clear_table()
494
+ draw_table()
495
+ }
496
+ if (!redraw) append_row(current_pod)
497
+ next
498
+ }
499
+ last_pod_line = 0
500
+ if ($0 ~ pattern) remaining = lines_after + 1
501
+ if (remaining > 0) {
502
+ if (is_trace($0)) {
503
+ remaining--
504
+ next
505
+ }
506
+ clear_table()
507
+ close_group()
508
+ put($0)
509
+ remaining--
510
+ draw_table()
511
+ }
512
+ }
513
+ END {
514
+ if (!handed_off && ready_pending()) hand_off()
515
+ close_group()
516
+ }
517
+ ' <"$fifo_dir/merged" &
518
+ filter_pid=$!
519
+
520
+ # stderr is duplicated: on its own for the native error and stack trace, and
521
+ # into the merged stream so both the debug log and the filter see it in
522
+ # chronological order with stdout.
523
+ tee -a "$error_log" <"$fifo_dir/stderr" >"$fifo_dir/merged" &
524
+ stderr_pid=$!
525
+
526
+ "$@" >"$fifo_dir/merged" 2>"$fifo_dir/stderr" || status=$?
527
+
528
+ # Drain both readers before the paths are printed, or the trace can still be
529
+ # in flight. Bounded: a command that leaks a child holding a stream open must
530
+ # not hang the deployment, and by then everything read has been written.
531
+ run_quiet_drain "$stderr_pid"
532
+ run_quiet_drain "$filter_pid"
533
+ rm -rf "$fifo_dir"
534
+
535
+ # A deployment can fail without the command failing. The in-pod lifecycle latches
536
+ # `container-status=error` and deliberately does not crash the container, so a step that
537
+ # reported a fatal runtime state can still exit 0 — and a green step here is a green
538
+ # GitHub Actions job on a deployment that never came up. The latch the filter recorded is
539
+ # therefore promoted to a failure exit of its own.
540
+ fatal=$(cat "$fail_flag" 2>/dev/null) || true
541
+ rm -f "$fail_flag"
542
+ if [ "$status" -eq 0 ] && [ -n "$fatal" ]; then
543
+ status=1
544
+ printf '%s✖ %s reported a fatal runtime state but exited 0 (%s)%s\n' \
545
+ "$RUN_QUIET_RED" "$label" "$fatal" "$RUN_QUIET_RESET" >&2
546
+ fi
547
+
548
+ if [ "$status" -ne 0 ]; then
549
+ run_quiet_error_trace "$debug_log" "$error_log"
550
+ # One line of why, never the trace: the filter drops trace lines from the window.
551
+ reason=$(grep -a -m1 -E '^[A-Za-z]*Error: |reported runtime status=' "$debug_log" 2>/dev/null | head -1) || true
552
+ printf '%s✖ %s failed (exit %s)%s\n' "$RUN_QUIET_RED" "$label" "$status" "$RUN_QUIET_RESET" >&2
553
+ [ -n "$reason" ] && printf '%s reason: %s%s\n' "$RUN_QUIET_RED" "$reason" "$RUN_QUIET_RESET" >&2
554
+ printf '%s error trace: %s\n debug log: %s%s\n' \
555
+ "$RUN_QUIET_RED" "$error_log" "$debug_log" "$RUN_QUIET_RESET" >&2
556
+ return "$status"
557
+ fi
558
+
559
+ rm -f "$debug_log" "$error_log"
560
+
561
+ return "$status"
562
+ }
563
+
564
+ # Appends the failing part of the merged log to the error trace, so the trace ends
565
+ # with the error rather than with whatever last wrote to stderr. Cuts from the first
566
+ # error marker; with no marker the tail stands in, which is where a logger-only
567
+ # failure reports itself.
568
+ run_quiet_error_trace() {
569
+ local debug_log="$1"
570
+ local error_log="$2"
571
+ local tail_lines="${3:-40}"
572
+ local first
573
+
574
+ # grep exits 1 when it matches nothing, and every deploy script runs under `set -e` with
575
+ # `pipefail`: unguarded, a failing step whose log carries no marker aborted this function
576
+ # before run_quiet could print the exit code and the two log paths, and the tail fallback
577
+ # below was unreachable. The no-match case is the fallback's trigger, not an error.
578
+ first=$(grep -a -n -m1 -E 'Error:|Error \[|^[[:space:]]+at |✖' "$debug_log" 2>/dev/null | cut -d: -f1) || true
579
+
580
+ printf -- '--- error trace (from merged log) ---\n' >>"$error_log"
581
+ if [ -n "$first" ]; then
582
+ tail -n "+$first" "$debug_log" >>"$error_log"
583
+ else
584
+ tail -n "$tail_lines" "$debug_log" >>"$error_log"
585
+ fi
586
+ }
587
+
588
+ run_quiet_drain() {
589
+ local pid="$1"
590
+
591
+ timeout 10 tail --pid="$pid" -f /dev/null 2>/dev/null || true
592
+ kill "$pid" 2>/dev/null || true
593
+ wait "$pid" 2>/dev/null || true
594
+ }