@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
@@ -4,26 +4,31 @@
4
4
  * @namespace UnderpostCluster
5
5
  */
6
6
 
7
- import { clusterTypeFactory, gatewayApiEnabledFactory, resolveReplicaCount } from '../server/conf.js';
8
- import { getNpmRootPath, HOST_VOLUME_ROOT } from '../server/environment.js';
9
- import { loggerFactory } from '../server/logger.js';
10
- import { shellExec } from '../server/process.js';
11
- import { crictlCommandFactory, resolveCriSocket } from '../server/cri.js';
7
+ import { clusterTypeFactory, gatewayApiEnabledFactory, resolveReplicaCount } from '../server/runtime/conf.js';
8
+ import { getNpmRootPath, HOST_VOLUME_ROOT } from '../server/runtime/environment.js';
9
+ import { loggerFactory } from '../server/ops/logger.js';
10
+ import { shellExec } from '../server/runtime/process.js';
11
+ import { crictlCommandFactory, resolveCriSocket } from '../server/ops/cri.js';
12
12
  import {
13
13
  runSELinuxCommands,
14
- selinuxContainerSharedContextCommandsFactory,
15
14
  selinuxEnforcingCommandsFactory,
16
15
  selinuxPackagesCommandFactory,
17
16
  selinuxRestoreconCommandFactory,
18
- } from '../server/selinux.js';
19
- import { UNDERPOST_GATEWAY, seedDefaultStatusPage } from '../server/underpost-gateway.js';
17
+ } from '../server/security/selinux.js';
18
+ import ContainerStorageService, {
19
+ containerStorageRootsFactory,
20
+ ensureContainerStorage,
21
+ localPathConfigCommandFactory,
22
+ localPathRootsFactory,
23
+ } from '../server/security/container-storage.js';
24
+ import { UNDERPOST_GATEWAY, seedDefaultStatusPage } from '../server/network/underpost-gateway.js';
20
25
  import {
21
26
  UNDERPOST_INGRESS,
22
27
  gatewayBackendFactory,
23
28
  underpostIngressConfFactory,
24
29
  underpostIngressHostMapFactory,
25
30
  underpostIngressManifestsFactory,
26
- } from '../server/underpost-ingress.js';
31
+ } from '../server/network/underpost-ingress.js';
27
32
  import { MONGODB_DEFAULT_REPLICA_COUNT } from '../db/mongo/MongooseDB.js';
28
33
  import { MongoBootstrap } from '../db/mongo/MongoBootstrap.js';
29
34
  import os from 'os';
@@ -35,8 +40,8 @@ const logger = loggerFactory(import.meta);
35
40
  const GATEWAY_API_RELEASE = 'v1.5.1';
36
41
  const ENVOY_GATEWAY_VERSION = 'v1.8.3';
37
42
  const CONTOUR_NAMESPACE = 'projectcontour';
38
- const KUBEADM_CONTAINER_MOUNT_PATHS = ['/etc/kubernetes', '/var/lib/etcd', '/var/lib/calico'];
39
- const HOST_VOLUME_PATHS = ['/data', '/opt/local-path-provisioner', HOST_VOLUME_ROOT];
43
+ const LOCAL_PATH_PROVISIONER_MANIFEST =
44
+ 'https://cdn.jsdelivr.net/gh/rancher/local-path-provisioner@master/deploy/local-path-storage.yaml';
40
45
  const K3S_SELINUX_PATHS = [
41
46
  '/usr/local/bin/k3s',
42
47
  '/etc/rancher',
@@ -45,15 +50,16 @@ const K3S_SELINUX_PATHS = [
45
50
  '/var/lib/cni',
46
51
  ];
47
52
 
48
- const shareWithContainers = (paths = []) => {
49
- for (const path of paths) shellExec(`sudo mkdir -p ${path}`);
50
- runSELinuxCommands(selinuxContainerSharedContextCommandsFactory(paths), { execute: shellExec });
51
- };
52
-
53
- const enforceSELinux = (paths = []) => {
53
+ // `semanage` and `restorecon` come from separate packages and neither is guaranteed on a minimal
54
+ // Rocky install. Installed before anything tries to register a mapping, because a missing
55
+ // `semanage` would otherwise turn every persistent labeling command into a hard failure.
56
+ const ensureSELinuxTooling = () =>
54
57
  shellExec(
55
58
  `if [ -f /etc/redhat-release ] && command -v dnf >/dev/null 2>&1 && { ! command -v restorecon >/dev/null 2>&1 || ! command -v semanage >/dev/null 2>&1; }; then ${selinuxPackagesCommandFactory()}; fi`,
56
59
  );
60
+
61
+ const enforceSELinux = (paths = []) => {
62
+ ensureSELinuxTooling();
57
63
  const commands = selinuxEnforcingCommandsFactory({ restorePaths: paths });
58
64
  runSELinuxCommands(commands, { execute: shellExec });
59
65
  };
@@ -112,9 +118,10 @@ class UnderpostCluster {
112
118
  * @param {boolean} [options.nodePort=false] - Expose enabled ready services (e.g. MongoDB 4.4, Valkey)
113
119
  * to the host/public network via their NodePort Service manifest. The node port value lives directly
114
120
  * in each manifest (mongodb-4.4/mongodb-nodeport.yaml, valkey/valkey-nodeport.yaml).
115
- * @param {string} [options.nodeSelector=''] - Pin the just-deployed StatefulSet (MongoDB 4.4 / Valkey)
116
- * to a specific Kubernetes node by name (e.g. 'localhost.localdomain'). Applied via a
117
- * `kubernetes.io/hostname` nodeSelector patch once the workload reports Ready.
121
+ * @param {string} [options.nodeName=''] - Pin the just-deployed StatefulSet (MongoDB 4.4 / Valkey)
122
+ * and the observability workloads to a specific Kubernetes node by name (e.g.
123
+ * 'localhost.localdomain'). Applied via a `kubernetes.io/hostname` nodeSelector patch once
124
+ * the workload reports Ready.
118
125
  * @memberof UnderpostCluster
119
126
  */
120
127
  async init(
@@ -154,7 +161,7 @@ class UnderpostCluster {
154
161
  hosts: '',
155
162
  replicas: '',
156
163
  nodePort: false,
157
- nodeSelector: '',
164
+ nodeName: '',
158
165
  },
159
166
  ) {
160
167
  if (options.initHost) return Underpost.cluster.initHost();
@@ -232,6 +239,12 @@ class UnderpostCluster {
232
239
  logger.info(
233
240
  `Detected existing ${runtime.type} cluster (${runtime.ready ? 'Ready' : 'NotReady'}); skipping initialization.`,
234
241
  );
242
+ // Initialization is skipped, but the labeling invariant is not: the node directories
243
+ // backing PersistentVolumes outlive the bring-up that created them, and a policy update,
244
+ // a full relabel or a directory recreated by kubelet resets them to the policy default.
245
+ // Re-asserting it costs a `semanage` lookup and a `restorecon` pass, mutates no workload,
246
+ // and never changes SELinux mode.
247
+ Underpost.cluster.ensureContainerStorageContexts();
235
248
  }
236
249
 
237
250
  // --- Kubeadm/Kind/K3s Cluster Initialization ---
@@ -265,7 +278,7 @@ class UnderpostCluster {
265
278
  } else if (options.kubeadm) {
266
279
  Underpost.cluster.config();
267
280
  Underpost.cluster.natSetup({ underpostRoot });
268
- shareWithContainers([...KUBEADM_CONTAINER_MOUNT_PATHS, ...HOST_VOLUME_PATHS]);
281
+ Underpost.cluster.ensureContainerStorageContexts({ controlPlane: true });
269
282
  logger.info('Initializing Kubeadm control plane...');
270
283
  // Set default values if not provided
271
284
  const podNetworkCidr = options.podNetworkCidr || '192.168.0.0/16';
@@ -293,18 +306,13 @@ class UnderpostCluster {
293
306
  // Untaint control plane node to allow scheduling pods
294
307
  const nodeName = os.hostname();
295
308
  shellExec(`kubectl taint nodes ${nodeName} node-role.kubernetes.io/control-plane:NoSchedule-`);
296
- // Install local-path-provisioner for dynamic PVCs
297
- logger.info('Installing local-path-provisioner...');
298
- shellExec(
299
- `kubectl apply -f https://cdn.jsdelivr.net/gh/rancher/local-path-provisioner@master/deploy/local-path-storage.yaml`,
300
- );
301
-
302
309
  // The CNI lands asynchronously, and the node stays NotReady until it
303
310
  // does. Block here so the deploy steps that follow (MongoDB and the
304
311
  // application workloads) schedule onto a node that can actually run
305
312
  // them, instead of racing the Calico rollout.
306
313
  logger.info('Waiting for the node to become Ready (Calico rollout)...');
307
314
  shellExec(`kubectl wait --for=condition=Ready node --all --timeout=300s`);
315
+ Underpost.cluster.ensureLocalPathProvisioner();
308
316
  } else {
309
317
  Underpost.cluster.config();
310
318
  Underpost.cluster.natSetup({ underpostRoot });
@@ -355,36 +363,19 @@ class UnderpostCluster {
355
363
  shellExec(`node ${underpostRoot}/bin/deploy kubeflow-spark-operator${options.kubeadm ? ' kubeadm' : ''}`);
356
364
  }
357
365
 
358
- if (options.grafana) {
359
- shellExec(`kubectl delete deployment grafana -n ${options.namespace} --ignore-not-found`);
360
- shellExec(`kubectl apply -k ${underpostRoot}/manifests/grafana -n ${options.namespace}`);
361
- const yaml = `${fs
362
- .readFileSync(`${underpostRoot}/manifests/grafana/deployment.yaml`, 'utf8')
363
- .replace('{{GF_SERVER_ROOT_URL}}', options.hosts.split(',')[0])}`;
364
- console.log(yaml);
365
- shellExec(`kubectl apply -f - -n ${options.namespace} <<'EOF'
366
- ${yaml}
367
- EOF
368
- `);
369
- }
370
-
371
- if (options.prom) {
372
- shellExec(`kubectl delete deployment prometheus --ignore-not-found`);
373
- shellExec(`kubectl delete configmap prometheus-config --ignore-not-found`);
374
- shellExec(`kubectl delete service prometheus --ignore-not-found`);
375
- // Prometheus server host: http://<prometheus-cluster-ip>:9090
376
- const yaml = `${fs.readFileSync(`${underpostRoot}/manifests/prometheus/deployment.yaml`, 'utf8').replace(
377
- '- targets: []',
378
- `- targets: [${options.prom
379
- .split(',')
380
- .map((host) => `'${host}'`)
381
- .join(',')}]`,
382
- )}`;
383
- console.log(yaml);
384
- shellExec(`kubectl apply -f - -n ${options.namespace} <<'EOF'
385
- ${yaml}
386
- EOF
387
- `);
366
+ // Grafana and Prometheus are two faces of one stack, so either flag
367
+ // converges the whole of it — including Alertmanager and the Blackbox
368
+ // Exporter, which the alert rules and probes are useless without. The
369
+ // scrape configuration is rendered from the deploy configuration and the
370
+ // event registry by the monitor CLI; `--prom [hosts]` only adds hosts
371
+ // that configuration does not name.
372
+ if (options.grafana || options.prom) {
373
+ await Underpost.monitor.deployObservability({
374
+ namespace: options.namespace,
375
+ dev: options.dev,
376
+ nodeName: options.nodeName,
377
+ hosts: typeof options.prom === 'string' ? options.prom : options.hosts,
378
+ });
388
379
  }
389
380
 
390
381
  if (options.valkey) {
@@ -396,11 +387,11 @@ EOF
396
387
  // The node port (32079) is set directly in the manifest.
397
388
  if (valkeyReady && options.nodePort)
398
389
  shellExec(`kubectl apply -f ${underpostRoot}/manifests/valkey/valkey-nodeport.yaml -n ${options.namespace}`);
399
- if (valkeyReady && options.nodeSelector)
390
+ if (valkeyReady && options.nodeName)
400
391
  Underpost.cluster.pinToNode({
401
392
  name: 'valkey-service',
402
393
  namespace: options.namespace,
403
- node: options.nodeSelector,
394
+ node: options.nodeName,
404
395
  });
405
396
  if (valkeyReady && serviceHost)
406
397
  Underpost.cluster.syncServiceConnectionEnv({
@@ -417,32 +408,32 @@ EOF
417
408
  // Encrypted store first; when no manifest exists the secret is seeded from its origin
418
409
  // seed path below. A manifest that exists but fails validation raises rather than
419
410
  // silently seeding stale credentials.
420
- if (!Underpost.secret.sops.applyIfPresent('mariadb-secret', options.namespace))
421
- shellExec(
422
- `sudo kubectl create secret generic mariadb-secret --from-file=username=/home/dd/engine/engine-private/mariadb-username --from-file=password=/home/dd/engine/engine-private/mariadb-password --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
423
- );
411
+ if (!Underpost.secret.applyIfPresent('mariadb-secret', options.namespace))
412
+ Underpost.secret.applyFromOriginSeed('mariadb-secret', options.namespace);
424
413
  shellExec(`kubectl delete statefulset mariadb-statefulset -n ${options.namespace} --ignore-not-found`);
425
414
 
426
415
  if (options.pullImage) Underpost.cluster.pullImage('mariadb:latest', options);
416
+ // The StatefulSet's volumeClaimTemplate is dynamically provisioned, so the data lands in
417
+ // a subdirectory of the local-path root and inherits that root's label.
418
+ Underpost.cluster.ensureContainerStorageContexts({ extraPaths: ['/data/mariadb'] });
427
419
  shellExec(`kubectl apply -f ${underpostRoot}/manifests/mariadb/storage-class.yaml -n ${options.namespace}`);
428
420
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/mariadb -n ${options.namespace}`);
429
421
  }
430
422
  if (options.mysql) {
431
- if (!Underpost.secret.sops.applyIfPresent('mysql-secret', options.namespace))
432
- shellExec(
433
- `sudo kubectl create secret generic mysql-secret --from-file=username=/home/dd/engine/engine-private/mysql-username --from-file=password=/home/dd/engine/engine-private/mysql-password --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
434
- );
435
- shellExec(`sudo mkdir -p /mnt/data`);
436
- shellExec(`sudo chmod 777 /mnt/data`);
437
- shellExec(`sudo chown -R $(whoami):$(whoami) /mnt/data`);
423
+ if (!Underpost.secret.applyIfPresent('mysql-secret', options.namespace))
424
+ Underpost.secret.applyFromOriginSeed('mysql-secret', options.namespace);
425
+ // The data directory is prepared, not opened up: a world-writable host path plus the
426
+ // operator's ownership was standing in for the SELinux label the container actually
427
+ // needed. `container_file_t` is what lets mysqld write here; 0755 root-owned is enough,
428
+ // because the image's entrypoint chowns the tree to its own uid on first start.
429
+ Underpost.cluster.ensureContainerStorageContexts({ extraPaths: ['/data/mysql'] });
438
430
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/mysql -n ${options.namespace}`);
439
431
  }
440
432
  if (options.postgresql) {
441
433
  if (options.pullImage) Underpost.cluster.pullImage('postgres:latest', options);
442
- if (!Underpost.secret.sops.applyIfPresent('postgres-secret', options.namespace))
443
- shellExec(
444
- `sudo kubectl create secret generic postgres-secret --from-file=password=/home/dd/engine/engine-private/postgresql-password --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
445
- );
434
+ if (!Underpost.secret.applyIfPresent('postgres-secret', options.namespace))
435
+ Underpost.secret.applyFromOriginSeed('postgres-secret', options.namespace);
436
+ Underpost.cluster.ensureContainerStorageContexts({ extraPaths: ['/data/postgresql'] });
446
437
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/postgresql -n ${options.namespace}`);
447
438
  }
448
439
  if (options.mongodb4) {
@@ -486,11 +477,11 @@ EOF
486
477
  shellExec(
487
478
  `kubectl apply -f ${underpostRoot}/manifests/mongodb-4.4/mongodb-nodeport.yaml -n ${options.namespace}`,
488
479
  );
489
- if (options.nodeSelector)
480
+ if (options.nodeName)
490
481
  Underpost.cluster.pinToNode({
491
482
  name: statefulSetName,
492
483
  namespace: options.namespace,
493
- node: options.nodeSelector,
484
+ node: options.nodeName,
494
485
  });
495
486
  if (serviceHost)
496
487
  Underpost.cluster.syncServiceConnectionEnv({
@@ -724,13 +715,107 @@ EOF
724
715
  return { type, ready, nodes };
725
716
  },
726
717
 
718
+ /**
719
+ * @method discoverLocalPathRoots
720
+ * @description Reads the node directories the local-path provisioner writes into, from its
721
+ * live ConfigMap. Every dynamically provisioned claim in this platform (Grafana, Prometheus,
722
+ * Alertmanager, IPFS, MariaDB) becomes a subdirectory of one of them, so the root has to be
723
+ * discovered rather than assumed — a wrong guess leaves those claims carrying the `/opt`
724
+ * policy default (`usr_t`), which no `container_t` pod can write.
725
+ * @returns {string[]} Configured node paths; empty when no provisioner is reachable.
726
+ * @memberof UnderpostCluster
727
+ */
728
+ discoverLocalPathRoots() {
729
+ for (const namespace of ContainerStorageService.LOCAL_PATH_NAMESPACES) {
730
+ const config = `${
731
+ shellExec(localPathConfigCommandFactory({ namespace }), {
732
+ stdout: true,
733
+ silent: true,
734
+ silentOnError: true,
735
+ disableLog: true,
736
+ }) || ''
737
+ }`.trim();
738
+ const roots = localPathRootsFactory(config);
739
+ if (roots.length > 0) return roots;
740
+ }
741
+ return [];
742
+ },
743
+
744
+ /**
745
+ * @method ensureContainerStorageContexts
746
+ * @description Makes SELinux compatibility an invariant of the storage lifecycle rather than
747
+ * a one-time bring-up step: creates the node directories this platform hands to containers
748
+ * (only when missing, so live data trees keep their ownership and mode), registers the
749
+ * persistent `container_file_t` mapping for each, and restores the trees.
750
+ *
751
+ * Idempotent and safe to call on every deploy. Never relabels paths outside the discovered
752
+ * set, and never changes SELinux mode.
753
+ * @param {object} [options]
754
+ * @param {boolean} [options.controlPlane=false] - Also cover the kubeadm control-plane trees
755
+ * bind-mounted into containers (`/etc/kubernetes`, `/var/lib/etcd`, `/var/lib/calico`).
756
+ * @param {string[]} [options.extraPaths=[]] - Additional node directories to include.
757
+ * @returns {string[]} The roots that were prepared.
758
+ * @memberof UnderpostCluster
759
+ */
760
+ ensureContainerStorageContexts(options = {}) {
761
+ const roots = containerStorageRootsFactory({
762
+ localPathRoots: Underpost.cluster.discoverLocalPathRoots(),
763
+ extraPaths: options.extraPaths || [],
764
+ controlPlane: options.controlPlane === true,
765
+ });
766
+ logger.info('Preparing container-mounted host storage', { roots });
767
+ // HOST_VOLUME_ROOT is the one root the deploy flow writes into unprivileged (it lives in the
768
+ // operator's home tree and receives each hostPath volume's contents), so it is created owned
769
+ // by the invoking user. The rest stay root-owned: their subdirectories are chowned by each
770
+ // workload's own init container, which is the single owner of that concern.
771
+ const { uid, gid } = os.userInfo();
772
+ const operatorRoots = roots.filter((root) => root === HOST_VOLUME_ROOT);
773
+ const systemRoots = roots.filter((root) => root !== HOST_VOLUME_ROOT);
774
+ if (systemRoots.length > 0) ensureContainerStorage(systemRoots, { execute: shellExec });
775
+ if (operatorRoots.length > 0)
776
+ ensureContainerStorage(operatorRoots, { execute: shellExec, owner: `${uid}:${gid}` });
777
+ return roots;
778
+ },
779
+
780
+ /**
781
+ * @method ensureLocalPathProvisioner
782
+ * @description Ensures dynamic local-path PVC provisioning is available.
783
+ * @returns {string} Namespace containing the ready provisioner.
784
+ * @memberof UnderpostCluster
785
+ */
786
+ ensureLocalPathProvisioner() {
787
+ const locations = ['local-path-storage', 'kube-system'];
788
+ let namespace = locations.find((candidate) =>
789
+ `${
790
+ shellExec(`kubectl get deployment local-path-provisioner -n ${candidate} -o name`, {
791
+ stdout: true,
792
+ silent: true,
793
+ silentOnError: true,
794
+ disableLog: true,
795
+ }) || ''
796
+ }`.trim(),
797
+ );
798
+
799
+ if (!namespace) {
800
+ logger.info('Installing local-path-provisioner');
801
+ shellExec(`kubectl apply -f ${LOCAL_PATH_PROVISIONER_MANIFEST}`);
802
+ namespace = 'local-path-storage';
803
+ }
804
+ shellExec(`kubectl rollout status deployment/local-path-provisioner -n ${namespace} --timeout=5m`);
805
+ // The provisioner's root exists (or is about to) only now, and its helper pod creates each
806
+ // claim directory by inheriting that root's label. Prepare it here so the first dynamically
807
+ // provisioned claim already lands on `container_file_t` instead of `/opt`'s `usr_t`.
808
+ Underpost.cluster.ensureContainerStorageContexts();
809
+ return namespace;
810
+ },
811
+
727
812
  /**
728
813
  * @method pinToNode
729
814
  * @description Pins a workload to a specific Kubernetes node by patching its
730
815
  * pod template with a `kubernetes.io/hostname` nodeSelector. General-purpose;
731
- * currently used to place the MongoDB 4.4 / Valkey StatefulSets on a chosen
732
- * node (`--node-selector`). The patch triggers a rolling reschedule onto the
733
- * target node.
816
+ * currently used to place the MongoDB 4.4 / Valkey StatefulSets and the
817
+ * observability Deployments on a chosen node (`--node-name`). The patch
818
+ * triggers a rolling reschedule onto the target node.
734
819
  * @param {object} params
735
820
  * @param {string} [params.kind='statefulset'] - Workload kind to patch.
736
821
  * @param {string} params.name - Workload name.
@@ -1383,6 +1468,16 @@ EOF
1383
1468
  config(options = { underpostRoot: '.' }) {
1384
1469
  const { underpostRoot } = options;
1385
1470
  console.log('Applying host configuration: SELinux, Docker, Containerd, and Sysctl settings.');
1471
+ // Label before enforcing, never after: flipping the mode first would put the host into
1472
+ // Enforcing with the storage trees still carrying the policy default, and every pod that
1473
+ // mounts one would start failing for real instead of only logging a denial.
1474
+ //
1475
+ // Registered on every run, not only at first cluster creation: the node directories backing
1476
+ // PersistentVolumes are recreated by resets, by `DirectoryOrCreate`, and by the local-path
1477
+ // helper pod long after `kubeadm init` ran, and each of those inherits the policy default
1478
+ // unless the mapping is already in the store.
1479
+ ensureSELinuxTooling();
1480
+ Underpost.cluster.ensureContainerStorageContexts();
1386
1481
  enforceSELinux(['/var/lib/kubelet', '/var/lib/containerd']);
1387
1482
 
1388
1483
  // Enable and start Docker and Kubelet services
@@ -1439,8 +1534,11 @@ EOF
1439
1534
  // forever (the upstream unit ships TimeoutStartSec=0).
1440
1535
  shellExec(`if systemctl is-active --quiet firewalld; then sudo systemctl disable --now firewalld; fi`);
1441
1536
 
1537
+ // Storage labeling precedes the Enforcing flip, so the mode is never activated over trees
1538
+ // that still carry the policy default.
1539
+ ensureSELinuxTooling();
1540
+ Underpost.cluster.ensureContainerStorageContexts();
1442
1541
  enforceSELinux(K3S_SELINUX_PATHS);
1443
- shareWithContainers(HOST_VOLUME_PATHS);
1444
1542
 
1445
1543
  // Disable swap. `swapoff -a` is a no-op without swap; the sed only edits
1446
1544
  // fstab when a swap line is present.
@@ -1714,6 +1812,10 @@ fi`);
1714
1812
  else logger.info(' -> Skipping (pass --remove-volume-host-paths to enable).');
1715
1813
 
1716
1814
  logger.info('Phase 2/7: Enforcing SELinux and restoring runtime contexts...');
1815
+ // The hostPath cleanup above emptied the volume trees; re-asserting the mapping here means
1816
+ // a rebuild starts from correctly labeled storage instead of inheriting the policy default.
1817
+ ensureSELinuxTooling();
1818
+ Underpost.cluster.ensureContainerStorageContexts();
1717
1819
  enforceSELinux(['/var/lib/kubelet', '/var/lib/containerd']);
1718
1820
 
1719
1821
  logger.info('Phase 3/7: Stopping host kubelet and container runtimes (kubeadm-scope only)...');
@@ -1916,7 +2018,7 @@ EOF`);
1916
2018
 
1917
2019
  // SOPS and Age for Git-native encrypted secret manifests. Owned by UnderpostSecret so the
1918
2020
  // same idempotent install backs `underpost secret --install-tools`.
1919
- Underpost.secret.sops.installTooling();
2021
+ Underpost.secret.installTooling();
1920
2022
 
1921
2023
  // Install snap
1922
2024
  shellExec(`sudo yum install -y snapd`);