@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.
- package/.dockerignore +1 -0
- package/.env.example +16 -0
- package/.github/workflows/coverall.cyberia.ci.yml +107 -0
- package/.github/workflows/cyberia-client.cd.yml +6 -18
- package/.github/workflows/cyberia-server.cd.yml +6 -18
- package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
- package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
- package/.github/workflows/engine-cyberia.cd.yml +6 -78
- package/.github/workflows/engine-cyberia.ci.yml +4 -5
- package/.github/workflows/ghpkg.ci.yml +42 -21
- package/.github/workflows/hardhat.ci.yml +12 -11
- package/.github/workflows/npmpkg.ci.yml +17 -15
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -16
- package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
- package/.github/workflows/release.cd.yml +2 -9
- package/.prettierignore +1 -0
- package/AGENTS.md +47 -0
- package/CHANGELOG.md +581 -2417
- package/CLI-HELP.md +416 -127
- package/Dockerfile +25 -9
- package/Dockerfile.dev +25 -9
- package/Dockerfile.test +4 -4
- package/README.md +21 -1
- package/bin/build.js +70 -43
- package/bin/build.template.js +8 -3
- package/bin/cyberia.js +372 -135
- package/bin/deploy.js +18 -104
- package/bin/index.js +372 -135
- package/compose.env +16 -0
- package/conf.js +93 -4
- package/deploy/cyberia-client/deploy.sh +47 -0
- package/deploy/cyberia-client/package.sh +18 -0
- package/deploy/cyberia-client/state.sh +14 -0
- package/deploy/cyberia-server/deploy.sh +47 -0
- package/deploy/cyberia-server/package.sh +18 -0
- package/deploy/cyberia-server/state.sh +14 -0
- package/deploy/dd-cyberia/deploy.sh +22 -0
- package/deploy/dd-cyberia/init.sh +55 -0
- package/deploy/dd-cyberia/package.sh +17 -0
- package/deploy/dd-cyberia/state.sh +14 -0
- package/deploy/dd-cyberia/sync-deploy.sh +116 -0
- package/deploy/lib/github-actions-logging.sh +594 -0
- package/deploy/lib/host.sh +185 -0
- package/deploy/lib/state.sh +62 -0
- package/deploy/pwa-microservices-template/deploy.sh +45 -0
- package/deploy/release/deploy.sh +32 -0
- package/deployment.yaml +7 -2
- package/docker-compose.yml +31 -37
- package/examples/static-page/README.md +19 -19
- package/examples/static-page/ssr-components/CustomPage.js +2 -2
- package/hardhat/hardhat.config.js +1 -6
- package/hardhat/package-lock.json +104 -43
- package/hardhat/package.json +3 -3
- package/manifests/alertmanager/deployment.yaml +81 -0
- package/manifests/blackbox-exporter/deployment.yaml +75 -0
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +36 -7
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +77 -0
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/grafana/deployment.yaml +26 -7
- package/manifests/grafana/kustomization.yaml +1 -0
- package/manifests/grafana/service.yaml +6 -1
- package/manifests/mariadb/pv.yaml +1 -0
- package/manifests/mongodb/statefulset.yaml +9 -2
- package/manifests/mysql/pv-pvc.yaml +14 -1
- package/manifests/postgresql/pv.yaml +12 -1
- package/manifests/postgresql/pvc.yaml +1 -0
- package/manifests/prometheus/deployment.yaml +18 -22
- package/package.json +83 -10
- package/scripts/audit-selinux.sh +64 -0
- package/scripts/event-monitor.sh +56 -0
- package/scripts/gpu-diag.sh +0 -0
- package/scripts/ip-info.sh +0 -0
- package/scripts/k3s-node-setup.sh +30 -14
- package/scripts/kubeadm-node-setup.sh +40 -31
- package/scripts/lxd-vm-setup.sh +0 -0
- package/scripts/maas-nat-firewalld.sh +0 -0
- package/scripts/maas-setup.sh +8 -8
- package/scripts/nat-iptables.sh +2 -0
- package/scripts/rhel-grpc-setup.sh +0 -0
- package/scripts/rocky-kickstart.sh +25 -9
- package/scripts/selinux-normalize.sh +907 -0
- package/scripts/shutdown-machine.sh +843 -0
- package/scripts/test-monitor.sh +3 -3
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +1 -1
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +2 -2
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +2 -2
- package/src/api/core/core.controller.js +1 -1
- package/src/api/core/core.router.js +2 -2
- package/src/api/core/core.service.js +2 -2
- package/src/api/crypto/crypto.controller.js +1 -1
- package/src/api/crypto/crypto.service.js +1 -1
- package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
- package/src/api/cyberia-action/cyberia-action.router.js +1 -1
- package/src/api/cyberia-action/cyberia-action.service.js +2 -2
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -1
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +1 -1
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +2 -2
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
- package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.service.js +2 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +1 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +1 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +2 -2
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +466 -0
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +63 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +16 -1
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +1 -1
- package/src/api/cyberia-instance/cyberia-instance.controller.js +4 -1
- package/src/api/cyberia-instance/cyberia-instance.router.js +15 -2
- package/src/api/cyberia-instance/cyberia-instance.service.js +45 -2
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +1 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +2 -2
- package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
- package/src/api/cyberia-map/cyberia-map.router.js +1 -1
- package/src/api/cyberia-map/cyberia-map.service.js +2 -2
- package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.router.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.service.js +2 -2
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
- package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
- package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
- package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +16 -29
- package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
- package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
- package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
- package/src/api/default/default.controller.js +1 -1
- package/src/api/default/default.router.js +1 -1
- package/src/api/default/default.service.js +2 -2
- package/src/api/document/document.controller.js +1 -1
- package/src/api/document/document.router.js +1 -1
- package/src/api/document/document.service.js +2 -2
- package/src/api/file/file.controller.js +1 -1
- package/src/api/file/file.router.js +1 -1
- package/src/api/file/file.service.js +2 -2
- package/src/api/instance/instance.controller.js +1 -1
- package/src/api/instance/instance.router.js +1 -1
- package/src/api/instance/instance.service.js +2 -2
- package/src/api/ipfs/ipfs.controller.js +1 -1
- package/src/api/ipfs/ipfs.router.js +2 -2
- package/src/api/ipfs/ipfs.service.js +2 -2
- package/src/api/object-layer/object-layer.controller.js +1 -1
- package/src/api/object-layer/object-layer.model.js +204 -3
- package/src/api/object-layer/object-layer.router.js +2 -2
- package/src/api/object-layer/object-layer.service.js +4 -17
- package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
- package/src/api/test/test.controller.js +1 -1
- package/src/api/test/test.service.js +1 -1
- package/src/api/user/guest.service.js +3 -3
- package/src/api/user/user.controller.js +1 -1
- package/src/api/user/user.router.js +2 -2
- package/src/api/user/user.service.js +4 -4
- package/src/api.js +5 -9
- package/src/cli/app.js +391 -0
- package/src/cli/baremetal.js +30 -36
- package/src/cli/client.js +306 -0
- package/src/cli/cloud-init.js +3 -3
- package/src/cli/cluster.js +242 -135
- package/src/cli/db.js +126 -67
- package/src/cli/deploy.js +158 -60
- package/src/cli/docker-compose.js +5 -5
- package/src/cli/domains.js +184 -0
- package/src/cli/dotenv-store.js +143 -0
- package/src/cli/event.js +2281 -0
- package/src/cli/fs.js +3 -3
- package/src/cli/host.js +672 -0
- package/src/cli/image.js +4 -7
- package/src/cli/index.js +426 -134
- package/src/cli/ipfs.js +34 -30
- package/src/cli/kickstart.js +1 -1
- package/src/cli/kubectl.js +218 -41
- package/src/cli/lxd.js +3 -3
- package/src/cli/monitor.js +1359 -26
- package/src/cli/package.js +90 -0
- package/src/cli/release.js +73 -34
- package/src/cli/repository.js +564 -367
- package/src/cli/run.js +362 -654
- package/src/cli/secrets.js +2158 -964
- package/src/cli/ssh.js +651 -331
- package/src/cli/state.js +394 -0
- package/src/cli/static.js +2 -2
- package/src/cli/system.js +26 -13
- package/src/cli/test.js +199 -125
- package/src/cli/vultr.js +623 -0
- package/src/cli/wireguard.js +2930 -0
- package/src/client/components/core/CalendarCore.js +53 -96
- package/src/client/components/core/Docs.js +258 -211
- package/src/client/components/core/FileExplorer.js +0 -21
- package/src/client/components/core/PanelForm.js +4 -4
- package/src/client/components/core/Repository.js +56 -0
- package/src/client/components/core/Translate.js +7 -0
- package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
- package/src/client/components/core/Wallet.js +0 -11
- package/src/client/components/core/Worker.js +7 -1
- package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +368 -0
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +35 -1
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +4 -0
- package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
- package/src/client/components/default/AppShellDefault.js +1 -1
- package/src/client/components/default/SettingsDefault.js +2 -2
- package/src/client/components/itemledger/SettingsItemledger.js +2 -2
- package/src/client/components/underpost/AppShellUnderpost.js +3 -2
- package/src/client/components/underpost/SettingsUnderpost.js +2 -2
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +17 -3
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +32 -5
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +1 -1
- package/src/client/public/cyberia-docs/CYBERIA.md +21 -1
- package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
- package/src/client/public/default/android-chrome-144x144.png +0 -0
- package/src/client/public/default/android-chrome-192x192.png +0 -0
- package/src/client/public/default/android-chrome-256x256.png +0 -0
- package/src/client/public/default/android-chrome-36x36.png +0 -0
- package/src/client/public/default/android-chrome-384x384.png +0 -0
- package/src/client/public/default/android-chrome-48x48.png +0 -0
- package/src/client/public/default/android-chrome-512x512.png +0 -0
- package/src/client/public/default/android-chrome-72x72.png +0 -0
- package/src/client/public/default/android-chrome-96x96.png +0 -0
- package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
- package/src/client/public/default/assets/background/white.jpg +0 -0
- package/src/client/public/default/browserconfig.xml +1 -1
- package/src/client/public/default/favicon-16x16.png +0 -0
- package/src/client/public/default/favicon-32x32.png +0 -0
- package/src/client/public/default/favicon-48x48.png +0 -0
- package/src/client/public/default/favicon.ico +0 -0
- package/src/client/public/default/manifest.webmanifest +5 -5
- package/src/client/public/default/mstile-144x144.png +0 -0
- package/src/client/public/default/mstile-150x150.png +0 -0
- package/src/client/public/default/mstile-310x150.png +0 -0
- package/src/client/public/default/mstile-310x310.png +0 -0
- package/src/client/public/default/mstile-70x70.png +0 -0
- package/src/client/public/default/yandex-browser-50x50.png +0 -0
- package/src/client/public/default/yandex-browser-manifest.json +1 -1
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +40 -0
- package/src/client/services/object-layer/object-layer.management.js +4 -4
- package/src/client/ssr/RootDocument.js +1 -1
- package/src/client/ssr/body/404.js +1 -1
- package/src/client/ssr/body/500.js +1 -1
- package/src/client/ssr/body/CacheControl.js +1 -1
- package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
- package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
- package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
- package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
- package/src/client/ssr/head/CryptokoynScripts.js +1 -1
- package/src/client/ssr/head/Css.js +1 -1
- package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
- package/src/client/ssr/head/DefaultScripts.js +1 -1
- package/src/client/ssr/head/ItemledgerScripts.js +1 -1
- package/src/client/ssr/head/Microdata.js +1 -1
- package/src/client/ssr/head/Production.js +1 -1
- package/src/client/ssr/head/Pwa.js +1 -1
- package/src/client/ssr/head/PwaItemledger.js +1 -1
- package/src/client/ssr/head/Seo.js +1 -1
- package/src/client/ssr/head/UnderpostScripts.js +1 -1
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
- package/src/client/ssr/views/Cyberia404.js +7 -5
- package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
- package/src/client/ssr/views/Maintenance.js +1 -1
- package/src/client/ssr/views/NoNetworkConnection.js +1 -1
- package/src/client/ssr/views/Test.js +1 -1
- package/src/client/sw/core.sw.js +20 -14
- package/src/client-builder/client-build-docs.js +61 -46
- package/src/client-builder/client-build-live.js +2 -2
- package/src/client-builder/client-build.js +58 -44
- package/src/client-builder/client-dev-server.js +3 -3
- package/src/client-builder/client-icons.js +2 -2
- package/src/client-builder/ssr.js +3 -3
- package/src/client.build.js +3 -6
- package/src/client.dev.js +3 -6
- package/src/db/DataBaseProvider.js +186 -3
- package/src/db/mariadb/MariaDB.js +3 -2
- package/src/db/mongo/MongoBootstrap.js +273 -101
- package/src/db/mongo/MongooseDB.js +11 -8
- package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
- package/src/grpc/cyberia/grpc-server.js +1 -1
- package/src/index.js +103 -23
- package/src/mailer/EmailRender.js +2 -2
- package/src/mailer/MailerInterceptor.js +87 -0
- package/src/mailer/MailerProvider.js +50 -6
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +1 -1
- package/src/projects/cyberia/besu-genesis-generator.js +3 -3
- package/src/projects/cyberia/catalog-cyberia.js +54 -6
- package/src/projects/cyberia/gemini-client.js +1 -1
- package/src/projects/cyberia/generate-saga.js +15 -24
- package/src/projects/cyberia/hot-reload-trigger.js +1 -1
- package/src/projects/cyberia/instance-data.js +22 -3
- package/src/projects/cyberia/ipfs-client.js +4 -4
- package/src/projects/cyberia/map-preview-generator.js +1 -1
- package/src/projects/cyberia/object-layer.js +12 -22
- package/src/projects/cyberia/semantic-layer-generator.js +1 -1
- package/src/projects/underpost/catalog-underpost.js +13 -2
- package/src/proxy.js +4 -7
- package/src/runtime/cyberia-client/Dockerfile +9 -4
- package/src/runtime/cyberia-client/Dockerfile.dev +8 -2
- package/src/runtime/cyberia-server/Dockerfile +9 -4
- package/src/runtime/cyberia-server/Dockerfile.dev +8 -2
- package/src/runtime/engine-cyberia/Dockerfile +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.test +4 -4
- package/src/runtime/engine-cyberia/compose.env +16 -0
- package/src/runtime/engine-cyberia/docker-compose.yml +31 -37
- package/src/runtime/express/Express.js +32 -27
- package/src/runtime/lampp/Lampp.js +22 -70
- package/src/runtime/nginx/Nginx.js +1 -1
- package/src/runtime/wp/Wp.js +16 -48
- package/src/server/{catalog.js → build/catalog.js} +15 -5
- package/src/server/build/coverage.js +117 -0
- package/src/server/build/execution.js +402 -0
- package/src/server/build/package.js +465 -0
- package/src/server/build/testing.js +528 -0
- package/src/server/{dns.js → network/dns.js} +241 -14
- package/src/server/network/forward-proxy.js +541 -0
- package/src/server/{middlewares.js → network/middlewares.js} +59 -4
- package/src/server/network/node-capability.js +98 -0
- package/src/server/{peer.js → network/peer.js} +3 -3
- package/src/server/{proxy.js → network/proxy.js} +7 -13
- package/src/server/network/router.js +356 -0
- package/src/server/{tls.js → network/tls.js} +2 -2
- package/src/server/network/underpost-compression.js +186 -0
- package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +26 -16
- package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +19 -3
- package/src/server/{cri.js → ops/cri.js} +2 -2
- package/src/server/ops/cron.js +949 -0
- package/src/server/ops/event-notification.js +284 -0
- package/src/server/{logger.js → ops/logger.js} +108 -23
- package/src/server/ops/monitoring.js +1724 -0
- package/src/server/ops/systemd.js +259 -0
- package/src/server/{conf.js → runtime/conf.js} +521 -520
- package/src/server/runtime/config-scope.js +215 -0
- package/src/server/runtime/environment.js +149 -0
- package/src/server/{process.js → runtime/process.js} +153 -13
- package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
- package/src/server/{runtime.js → runtime/runtime.js} +12 -8
- package/src/server/{start.js → runtime/start.js} +128 -39
- package/src/server/{auth.js → security/auth.js} +7 -8
- package/src/server/security/container-storage.js +382 -0
- package/src/server/{crypto.js → security/crypto.js} +1 -1
- package/src/server/security/selinux.js +185 -0
- package/src/server/{backup.js → storage/backup.js} +17 -8
- package/src/server/{data-query.js → storage/data-query.js} +1 -1
- package/src/server/{downloader.js → storage/downloader.js} +2 -2
- package/src/server/storage/repository.js +68 -0
- package/src/server.js +4 -7
- package/src/ws/IoInterface.js +1 -1
- package/src/ws/IoServer.js +1 -1
- package/src/ws/core/core.ws.connection.js +1 -1
- package/src/ws/core/core.ws.emit.js +1 -1
- package/src/ws/core/core.ws.server.js +1 -1
- package/src/ws/default/default.ws.connection.js +1 -1
- package/src/ws/default/default.ws.emit.js +1 -1
- package/src/ws/default/default.ws.server.js +1 -1
- package/test/e2e/event-e2e-public-ingress-down.js +45 -0
- package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
- package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
- package/test/{api.test.js → integration/app/api.test.js} +33 -14
- package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +30 -0
- package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +2 -1
- package/test/integration/app/cyberia/cyberia-load.test.js +467 -0
- package/test/integration/app/cyberia/fallback-world-capture.test.js +253 -0
- package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
- package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
- package/test/integration/infra/1-security/config-scope.test.js +305 -0
- package/test/integration/infra/1-security/container-storage.test.js +356 -0
- package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
- package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
- package/test/integration/infra/1-security/selinux.test.js +69 -0
- package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
- package/test/integration/infra/1-security/systemd-service.test.js +70 -0
- package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
- package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
- package/test/integration/infra/2-network/node-capability.test.js +182 -0
- package/test/integration/infra/2-network/wireguard-cli.test.js +1163 -0
- package/test/integration/infra/2-network/wireguard-edge.test.js +1731 -0
- package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
- package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
- package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
- package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
- package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
- package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
- package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +47 -6
- package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +56 -4
- package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
- package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
- package/test/integration/infra/5-observability/event-notification.test.js +197 -0
- package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
- package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
- package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
- package/test/support/shell-harness.js +73 -0
- package/test/unit/build-template.test.js +97 -0
- package/test/unit/build-workflow-offline.test.js +132 -0
- package/test/unit/catalog.test.js +71 -0
- package/test/unit/client-build-docs.test.js +334 -0
- package/test/unit/conf-loading.test.js +303 -0
- package/test/unit/conf-resolution.test.js +979 -0
- package/test/unit/coverage-artifact.test.js +130 -0
- package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
- package/test/unit/deploy-env-resolution.test.js +38 -0
- package/test/unit/deploy-log-table.test.js +447 -0
- package/test/unit/execution-profiles.test.js +219 -0
- package/test/unit/fleet-sync-source.test.js +149 -0
- package/test/unit/logger-redaction.test.js +112 -0
- package/test/unit/package.test.js +403 -0
- package/test/unit/prepare-host.test.js +299 -0
- package/test/unit/process-environment.test.js +18 -0
- package/test/unit/propagation-message.test.js +78 -0
- package/test/unit/redeploy-plan.test.js +24 -0
- package/test/unit/release-bump.test.js +474 -0
- package/test/unit/ssh-output-redaction.test.js +28 -0
- package/test/unit/start-options.test.js +46 -0
- package/test/unit/test-tiers.test.js +193 -0
- package/vitest.config.js +58 -0
- package/.nycrc +0 -9
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
- package/manifests/mongodb/pv-pvc.yaml +0 -59
- package/scripts/link-local-underpost-cli.sh +0 -6
- package/src/api/user/user.build.js +0 -16
- package/src/cli/env.js +0 -177
- package/src/client/components/core/Blockchain.js +0 -41
- package/src/client/components/core/Blog.js +0 -9
- package/src/client/components/core/KeyboardAvoidance.js +0 -145
- package/src/client/public/default/assets/background/dark.jpg +0 -0
- package/src/client/public/default/assets/background/white0-min.jpg +0 -0
- package/src/client/public/default/assets/background/white0.jpg +0 -0
- package/src/client/public/doc/favicon.ico +0 -0
- package/src/client/public/doc/sitemap +0 -148
- package/src/server/cron.js +0 -476
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
import dotenv from 'dotenv';
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import shell from 'shelljs';
|
|
9
|
+
|
|
10
|
+
import UnderpostRelease, { bumpAuxiliaryFiles } from '../../src/cli/release.js';
|
|
11
|
+
import UnderpostRepository from '../../src/cli/repository.js';
|
|
12
|
+
import { Dns } from '../../src/server/network/dns.js';
|
|
13
|
+
|
|
14
|
+
const DOC_ROOT = 'src/client/public';
|
|
15
|
+
const VERSION_HEADER = /\*\*(?:Current )?[Vv]ersion:\*\* (\d+\.\d+\.\d+)/;
|
|
16
|
+
|
|
17
|
+
// `bumpp` mutates package.json and every lockfile it is handed, so the release
|
|
18
|
+
// pipeline drives a stand-in and the file list it was asked to bump is asserted.
|
|
19
|
+
const bumpped = vi.hoisted(() => []);
|
|
20
|
+
vi.mock('bumpp', () => ({
|
|
21
|
+
versionBump: async (options) => {
|
|
22
|
+
bumpped.push(options);
|
|
23
|
+
return { updatedFiles: options.files };
|
|
24
|
+
},
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
const markdownFiles = (dir) => {
|
|
28
|
+
if (!fs.existsSync(dir)) return [];
|
|
29
|
+
const out = [];
|
|
30
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
31
|
+
const full = path.join(dir, entry.name);
|
|
32
|
+
if (entry.isDirectory()) out.push(...markdownFiles(full));
|
|
33
|
+
else if (entry.isFile() && entry.name.endsWith('.md')) out.push(full);
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
describe('release version bump targets', () => {
|
|
39
|
+
const version = JSON.parse(fs.readFileSync('package.json', 'utf8')).version;
|
|
40
|
+
|
|
41
|
+
it('bumps every shipped doc that stamps the current version in its header', () => {
|
|
42
|
+
// A doc tree the target table does not name is bumped by nothing, and the stale
|
|
43
|
+
// header only surfaces after the release is out.
|
|
44
|
+
const stamped = markdownFiles(DOC_ROOT).filter(
|
|
45
|
+
(file) => fs.readFileSync(file, 'utf8').match(VERSION_HEADER)?.[1] === version,
|
|
46
|
+
);
|
|
47
|
+
const bumped = new Set(bumpAuxiliaryFiles(version, '0.0.0', { dryRun: true }).map(({ file }) => file));
|
|
48
|
+
|
|
49
|
+
for (const file of stamped) expect(bumped.has(file), file).to.equal(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('reports nothing at all when the version does not move', () => {
|
|
53
|
+
expect(bumpAuxiliaryFiles(version, version, { dryRun: true })).to.deep.equal([]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('leaves every file on disk untouched under a dry run', () => {
|
|
57
|
+
const written = vi.spyOn(fs, 'writeFileSync');
|
|
58
|
+
try {
|
|
59
|
+
bumpAuxiliaryFiles(version, '0.0.0', { dryRun: true });
|
|
60
|
+
expect(written.mock.calls.length).to.equal(0);
|
|
61
|
+
} finally {
|
|
62
|
+
written.mockRestore();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('rewrites only the occurrences carrying the pre-bump version', () => {
|
|
67
|
+
// A doc naming several historical tags must keep them; only the version the
|
|
68
|
+
// release is moving away from is a bump target.
|
|
69
|
+
const readme = ['[]', 'ci/cd cli v3.2.9'].join(
|
|
70
|
+
'\n',
|
|
71
|
+
);
|
|
72
|
+
const files = new Map([['README.md', readme]]);
|
|
73
|
+
vi.spyOn(fs, 'existsSync').mockImplementation((filePath) => files.has(`${filePath}`));
|
|
74
|
+
vi.spyOn(fs, 'readdirSync').mockReturnValue([]);
|
|
75
|
+
vi.spyOn(fs, 'readFileSync').mockImplementation((filePath) => files.get(`${filePath}`));
|
|
76
|
+
const writes = new Map();
|
|
77
|
+
vi.spyOn(fs, 'writeFileSync').mockImplementation((filePath, value) => writes.set(`${filePath}`, value));
|
|
78
|
+
try {
|
|
79
|
+
expect(bumpAuxiliaryFiles('3.2.9', '3.3.0')).to.deep.equal([{ file: 'README.md', count: 2 }]);
|
|
80
|
+
expect(writes.get('README.md')).to.include('package/underpost/3.3.0');
|
|
81
|
+
expect(writes.get('README.md')).to.include('ci/cd cli v3.3.0');
|
|
82
|
+
} finally {
|
|
83
|
+
vi.restoreAllMocks();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('preserves narrative references to other versions', () => {
|
|
88
|
+
const files = new Map([['README.md', 'ci/cd cli v3.2.9 — upgrading from ci/cd cli v3.1.0']]);
|
|
89
|
+
vi.spyOn(fs, 'existsSync').mockImplementation((filePath) => files.has(`${filePath}`));
|
|
90
|
+
vi.spyOn(fs, 'readdirSync').mockReturnValue([]);
|
|
91
|
+
vi.spyOn(fs, 'readFileSync').mockImplementation((filePath) => files.get(`${filePath}`));
|
|
92
|
+
const writes = new Map();
|
|
93
|
+
vi.spyOn(fs, 'writeFileSync').mockImplementation((filePath, value) => writes.set(`${filePath}`, value));
|
|
94
|
+
try {
|
|
95
|
+
expect(bumpAuxiliaryFiles('3.2.9', '3.3.0')).to.deep.equal([{ file: 'README.md', count: 1 }]);
|
|
96
|
+
expect(writes.get('README.md')).to.equal('ci/cd cli v3.3.0 — upgrading from ci/cd cli v3.1.0');
|
|
97
|
+
} finally {
|
|
98
|
+
vi.restoreAllMocks();
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('never rewrites the changelog, logs, vendored trees or private env files', () => {
|
|
103
|
+
// These paths hold history, runtime output and secrets: a regex sweep over
|
|
104
|
+
// them is destructive in a way no release needs.
|
|
105
|
+
const skipped = [
|
|
106
|
+
'CHANGELOG.md',
|
|
107
|
+
'logs/start.js/all.log',
|
|
108
|
+
'node_modules/pkg/README.md',
|
|
109
|
+
'.git/COMMIT_EDITMSG',
|
|
110
|
+
'engine-private/conf/dd-cron/.env.production',
|
|
111
|
+
];
|
|
112
|
+
vi.spyOn(fs, 'existsSync').mockReturnValue(true);
|
|
113
|
+
vi.spyOn(fs, 'readdirSync').mockImplementation((dir) =>
|
|
114
|
+
`${dir}` === 'logs'
|
|
115
|
+
? skipped.map((file) => ({ name: path.basename(file), isDirectory: () => false, isFile: () => true }))
|
|
116
|
+
: [],
|
|
117
|
+
);
|
|
118
|
+
vi.spyOn(fs, 'readFileSync').mockReturnValue('ci/cd cli v3.2.9');
|
|
119
|
+
const written = vi.spyOn(fs, 'writeFileSync').mockImplementation(() => undefined);
|
|
120
|
+
try {
|
|
121
|
+
bumpAuxiliaryFiles('3.2.9', '3.3.0');
|
|
122
|
+
for (const file of written.mock.calls.map(([filePath]) => `${filePath}`)) {
|
|
123
|
+
expect(
|
|
124
|
+
skipped.some((skip) => file.includes(skip)),
|
|
125
|
+
file,
|
|
126
|
+
).to.equal(false);
|
|
127
|
+
}
|
|
128
|
+
} finally {
|
|
129
|
+
vi.restoreAllMocks();
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Every release command is a chain of host commands against /home/dd. The suite
|
|
135
|
+
// asserts the command vector and its ordering; nothing is allowed to reach the
|
|
136
|
+
// real shell, the real repositories or the real production env file.
|
|
137
|
+
describe('release pipeline commands', () => {
|
|
138
|
+
let commands;
|
|
139
|
+
let directories;
|
|
140
|
+
|
|
141
|
+
const PACKAGE = { version: '3.2.9' };
|
|
142
|
+
|
|
143
|
+
beforeEach(() => {
|
|
144
|
+
commands = [];
|
|
145
|
+
directories = [];
|
|
146
|
+
bumpped.length = 0;
|
|
147
|
+
vi.spyOn(shell, 'exec').mockImplementation((command) => {
|
|
148
|
+
commands.push(command);
|
|
149
|
+
return { code: 0, stdout: '', stderr: '', toString: () => '' };
|
|
150
|
+
});
|
|
151
|
+
vi.spyOn(shell, 'cd').mockImplementation((dir) => directories.push(`${dir}`));
|
|
152
|
+
// `release build` and `release deploy` load dd-cron's production env with
|
|
153
|
+
// `override: true`; on a checkout that carries it, that would replace this
|
|
154
|
+
// process's own environment with live deploy credentials.
|
|
155
|
+
vi.spyOn(dotenv, 'config').mockReturnValue({ parsed: {} });
|
|
156
|
+
vi.spyOn(UnderpostRepository.API, 'clean').mockImplementation(() => undefined);
|
|
157
|
+
vi.spyOn(UnderpostRepository.API, 'initLocalRepo').mockImplementation(() => undefined);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
afterEach(() => vi.restoreAllMocks());
|
|
161
|
+
|
|
162
|
+
// `buildAndTestTemplate` waits 5.5s for the template dev server to write its
|
|
163
|
+
// startup log. The wait is the only real time in the pipeline, so it is faked
|
|
164
|
+
// rather than slept through.
|
|
165
|
+
const runTemplateBuild = async (...args) => {
|
|
166
|
+
vi.useFakeTimers({ toFake: ['setTimeout'] });
|
|
167
|
+
try {
|
|
168
|
+
const pending = UnderpostRelease.API.build(...args);
|
|
169
|
+
await vi.advanceTimersByTimeAsync(6000);
|
|
170
|
+
return await pending;
|
|
171
|
+
} finally {
|
|
172
|
+
vi.useRealTimers();
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const stubPackageJson = () => {
|
|
177
|
+
vi.spyOn(fs, 'readFileSync').mockImplementation((filePath) =>
|
|
178
|
+
`${filePath}` === 'package.json' ? JSON.stringify(PACKAGE) : '',
|
|
179
|
+
);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
describe('build', () => {
|
|
183
|
+
it('previews the canonical and auxiliary changes without touching the working tree', async () => {
|
|
184
|
+
stubPackageJson();
|
|
185
|
+
vi.spyOn(fs, 'existsSync').mockReturnValue(false);
|
|
186
|
+
vi.spyOn(fs, 'readdirSync').mockReturnValue([]);
|
|
187
|
+
const written = vi.spyOn(fs, 'writeFileSync').mockImplementation(() => undefined);
|
|
188
|
+
|
|
189
|
+
const result = await UnderpostRelease.API.build('3.3.0', { dryRun: true });
|
|
190
|
+
|
|
191
|
+
expect(result).to.deep.equal({ from: '3.2.9', to: '3.3.0', files: [], dryRun: true });
|
|
192
|
+
expect(bumpped.length).to.equal(0);
|
|
193
|
+
expect(written.mock.calls.length).to.equal(0);
|
|
194
|
+
expect(commands.length).to.equal(0);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('lists the manifests whose canonical version would move', async () => {
|
|
198
|
+
const manifests = new Map([
|
|
199
|
+
['package.json', JSON.stringify(PACKAGE)],
|
|
200
|
+
['hardhat/package.json', JSON.stringify({ version: '3.2.9' })],
|
|
201
|
+
['package-lock.json', JSON.stringify({ version: '3.3.0' })],
|
|
202
|
+
]);
|
|
203
|
+
vi.spyOn(fs, 'readFileSync').mockImplementation((filePath) => {
|
|
204
|
+
if (manifests.has(`${filePath}`)) return manifests.get(`${filePath}`);
|
|
205
|
+
throw new Error(`ENOENT ${filePath}`);
|
|
206
|
+
});
|
|
207
|
+
vi.spyOn(fs, 'existsSync').mockReturnValue(false);
|
|
208
|
+
vi.spyOn(fs, 'readdirSync').mockReturnValue([]);
|
|
209
|
+
|
|
210
|
+
await UnderpostRelease.API.build('3.3.0', { dryRun: true });
|
|
211
|
+
|
|
212
|
+
expect(commands.length).to.equal(0);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('defaults to the version already in package.json', async () => {
|
|
216
|
+
stubPackageJson();
|
|
217
|
+
vi.spyOn(fs, 'existsSync').mockReturnValue(false);
|
|
218
|
+
vi.spyOn(fs, 'readdirSync').mockReturnValue([]);
|
|
219
|
+
|
|
220
|
+
const result = await UnderpostRelease.API.build(undefined, { dryRun: true });
|
|
221
|
+
|
|
222
|
+
expect(result).to.include({ from: '3.2.9', to: '3.2.9' });
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('aborts the whole release when the template smoke test fails', async () => {
|
|
226
|
+
stubPackageJson();
|
|
227
|
+
vi.spyOn(fs, 'existsSync').mockReturnValue(false);
|
|
228
|
+
vi.spyOn(fs, 'readdirSync').mockReturnValue([]);
|
|
229
|
+
vi.spyOn(fs, 'removeSync').mockImplementation(() => undefined);
|
|
230
|
+
vi.spyOn(fs, 'writeFileSync').mockImplementation(() => undefined);
|
|
231
|
+
vi.spyOn(Dns, 'getLocalIPv4Address').mockReturnValue('10.0.0.8');
|
|
232
|
+
|
|
233
|
+
expect(await runTemplateBuild('3.3.0')).to.equal(undefined);
|
|
234
|
+
// The template log is absent, so the runner result is empty and the build
|
|
235
|
+
// must stop before bumpp and before any downstream regeneration.
|
|
236
|
+
expect(bumpped.length).to.equal(0);
|
|
237
|
+
expect(commands.some((command) => command.startsWith('node bin/deploy cli-docs'))).to.equal(false);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('bumps and regenerates once the template starts cleanly', async () => {
|
|
241
|
+
const envExample = 'DB_HOST=127.0.0.1\nDB_USER=root\nDB_PASSWORD=\nVALKEY_HOST=127.0.0.1\n';
|
|
242
|
+
const writes = new Map();
|
|
243
|
+
vi.spyOn(fs, 'existsSync').mockImplementation((filePath) => `${filePath}`.endsWith('logs/start.js/all.log'));
|
|
244
|
+
vi.spyOn(fs, 'readFileSync').mockImplementation((filePath) => {
|
|
245
|
+
if (`${filePath}` === 'package.json') return JSON.stringify(PACKAGE);
|
|
246
|
+
if (`${filePath}`.endsWith('.env.example')) return envExample;
|
|
247
|
+
if (`${filePath}`.endsWith('all.log')) return 'server listening\n';
|
|
248
|
+
return '';
|
|
249
|
+
});
|
|
250
|
+
vi.spyOn(fs, 'readdirSync').mockReturnValue([]);
|
|
251
|
+
vi.spyOn(fs, 'removeSync').mockImplementation(() => undefined);
|
|
252
|
+
vi.spyOn(fs, 'writeFileSync').mockImplementation((filePath, value) => writes.set(`${filePath}`, value));
|
|
253
|
+
vi.spyOn(Dns, 'getLocalIPv4Address').mockReturnValue('10.0.0.8');
|
|
254
|
+
|
|
255
|
+
const result = await runTemplateBuild('3.3.0', {
|
|
256
|
+
mongoHost: 'mongo.fixture.test',
|
|
257
|
+
mongoUser: 'fixture',
|
|
258
|
+
mongoPassword: 'secret',
|
|
259
|
+
valkeyHost: 'valkey.fixture.test',
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
expect(result).to.include({ from: '3.2.9', to: '3.3.0', dryRun: false });
|
|
263
|
+
expect(bumpped[0].files).to.include('package.json').and.to.include('hardhat/package-lock.json');
|
|
264
|
+
expect(bumpped[0]).to.include({ release: '3.3.0', commit: false, tag: false, push: false, confirm: false });
|
|
265
|
+
|
|
266
|
+
const templateEnv = writes.get('../pwa-microservices-template/.env.example');
|
|
267
|
+
expect(templateEnv).to.include('DB_HOST=mongo.fixture.test');
|
|
268
|
+
expect(templateEnv).to.include('DB_USER=fixture');
|
|
269
|
+
expect(templateEnv).to.include('DB_PASSWORD=secret');
|
|
270
|
+
expect(templateEnv).to.include('VALKEY_HOST=valkey.fixture.test');
|
|
271
|
+
// The example ships 127.0.0.1; the smoke test has to reach the host over
|
|
272
|
+
// the address the containers can route to.
|
|
273
|
+
expect(templateEnv).not.to.include('127.0.0.1');
|
|
274
|
+
expect(templateEnv).to.include('ENABLE_FILE_LOGS=true');
|
|
275
|
+
|
|
276
|
+
expect(commands).to.include('node bin/deploy cli-docs 3.2.9 3.3.0');
|
|
277
|
+
expect(commands).to.include('node bin cmt --changelog-build');
|
|
278
|
+
// The default conf is generated and removed again — leaving it behind
|
|
279
|
+
// makes the next `dd` fan-out build a deploy the release never declared.
|
|
280
|
+
expect(commands.filter((command) => command.includes('rm -rf ./engine-private/conf/dd-default')).length).to.equal(
|
|
281
|
+
2,
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('runs the template smoke test in an isolated environment', async () => {
|
|
286
|
+
vi.spyOn(fs, 'existsSync').mockReturnValue(false);
|
|
287
|
+
vi.spyOn(fs, 'readFileSync').mockImplementation((filePath) =>
|
|
288
|
+
`${filePath}` === 'package.json' ? JSON.stringify(PACKAGE) : '',
|
|
289
|
+
);
|
|
290
|
+
vi.spyOn(fs, 'readdirSync').mockReturnValue([]);
|
|
291
|
+
vi.spyOn(fs, 'removeSync').mockImplementation(() => undefined);
|
|
292
|
+
vi.spyOn(fs, 'writeFileSync').mockImplementation(() => undefined);
|
|
293
|
+
vi.spyOn(Dns, 'getLocalIPv4Address').mockReturnValue(null);
|
|
294
|
+
|
|
295
|
+
await runTemplateBuild('3.3.0');
|
|
296
|
+
|
|
297
|
+
const devCommand = commands.find((command) => command.includes('npm run dev'));
|
|
298
|
+
expect(devCommand).to.include('env -i HOME="$HOME" PATH="$PATH"');
|
|
299
|
+
expect(devCommand).to.include('ENABLE_FILE_LOGS=true');
|
|
300
|
+
expect(commands.filter((command) => command.startsWith('node bin run kill')).length).to.equal(8);
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
describe('ci', () => {
|
|
305
|
+
it('strips every accepted deploy id prefix down to one repository name', async () => {
|
|
306
|
+
for (const deployId of ['cyberia', 'dd-cyberia', 'engine-cyberia']) {
|
|
307
|
+
commands = [];
|
|
308
|
+
const { triggerCmd } = await UnderpostRelease.API.ci(deployId, 'fixture message');
|
|
309
|
+
expect(triggerCmd, deployId).to.include('/engine-cyberia');
|
|
310
|
+
expect(commands, deployId).to.include('node bin/build dd-cyberia');
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('replaces the template git directory with the bare clone of the target repository', async () => {
|
|
315
|
+
await UnderpostRelease.API.ci('core', 'fixture message');
|
|
316
|
+
expect(commands).to.include('rm -rf ./.git');
|
|
317
|
+
expect(commands).to.include('mv ../engine-core.git ./.git');
|
|
318
|
+
expect(commands).to.include('git config --local core.bare false');
|
|
319
|
+
expect(directories).to.include('/home/dd/pwa-microservices-template');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('falls back to the engine changelog message when none is passed', async () => {
|
|
323
|
+
vi.spyOn(shell, 'exec').mockImplementation((command) => {
|
|
324
|
+
commands.push(command);
|
|
325
|
+
const stdout = command.includes('--changelog-msg') ? ' generated message \n' : '';
|
|
326
|
+
return { code: 0, stdout, stderr: '', toString: () => stdout };
|
|
327
|
+
});
|
|
328
|
+
const { triggerCmd } = await UnderpostRelease.API.ci('core');
|
|
329
|
+
expect(triggerCmd).to.include('git commit -m "generated message"');
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('falls back to a generic message when the changelog yields nothing', async () => {
|
|
333
|
+
const { triggerCmd } = await UnderpostRelease.API.ci('core', ' ');
|
|
334
|
+
expect(triggerCmd).to.include('git commit -m "Update engine-core repository"');
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
describe('pwa', () => {
|
|
339
|
+
it('re-clones, rebuilds and stages the template', async () => {
|
|
340
|
+
const { triggerCmd } = await UnderpostRelease.API.pwa('fixture message');
|
|
341
|
+
expect(commands).to.include('sudo rm -rf /home/dd/pwa-microservices-template');
|
|
342
|
+
expect(commands).to.include('npm run build:template');
|
|
343
|
+
expect(commands).to.include('git add .');
|
|
344
|
+
expect(triggerCmd).to.include('git commit -m "fixture message"');
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it('falls back to the engine changelog message', async () => {
|
|
348
|
+
vi.spyOn(shell, 'exec').mockImplementation((command) => {
|
|
349
|
+
commands.push(command);
|
|
350
|
+
const stdout = command.includes('--changelog-msg') ? 'changelog line' : '';
|
|
351
|
+
return { code: 0, stdout, stderr: '', toString: () => stdout };
|
|
352
|
+
});
|
|
353
|
+
const { triggerCmd } = await UnderpostRelease.API.pwa();
|
|
354
|
+
expect(triggerCmd).to.include('git commit -m "changelog line"');
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('falls back to a generic message', async () => {
|
|
358
|
+
const { triggerCmd } = await UnderpostRelease.API.pwa('');
|
|
359
|
+
expect(triggerCmd).to.include('Update pwa-microservices-template repository');
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
describe('deploy', () => {
|
|
364
|
+
it('syncs the secrets, commits and pushes both repositories', async () => {
|
|
365
|
+
const previous = process.env.GITHUB_USERNAME;
|
|
366
|
+
process.env.GITHUB_USERNAME = 'fixture-org';
|
|
367
|
+
try {
|
|
368
|
+
await UnderpostRelease.API.deploy('3.3.0');
|
|
369
|
+
// Host configuration, loaded by domain rather than by a hardcoded env-file path.
|
|
370
|
+
expect(commands).to.include('node bin host load');
|
|
371
|
+
expect(commands).to.include(`node bin cmt . ci package-pwa-microservices-template 'New release v:3.3.0'`);
|
|
372
|
+
expect(commands).to.include('node bin push . fixture-org/engine');
|
|
373
|
+
expect(commands).to.include('cd ./engine-private && node ../bin push . fixture-org/engine-private');
|
|
374
|
+
} finally {
|
|
375
|
+
if (previous === undefined) delete process.env.GITHUB_USERNAME;
|
|
376
|
+
else process.env.GITHUB_USERNAME = previous;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// A document root that was never materialized is what Apache turns into a blanket 403, and the
|
|
383
|
+
// 403 carries nothing naming this step — so the branch that skipped provisioning has to be
|
|
384
|
+
// distinguishable in the log it leaves behind.
|
|
385
|
+
describe('site root provisioning', () => {
|
|
386
|
+
let commands;
|
|
387
|
+
|
|
388
|
+
beforeEach(() => {
|
|
389
|
+
commands = [];
|
|
390
|
+
vi.spyOn(shell, 'exec').mockImplementation((command) => {
|
|
391
|
+
commands.push(command);
|
|
392
|
+
return { code: 0, stdout: '', stderr: '', toString: () => '' };
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
afterEach(() => vi.restoreAllMocks());
|
|
397
|
+
|
|
398
|
+
it('separates an unresolved conf reference from an unreachable remote', () => {
|
|
399
|
+
const isRemote = vi.spyOn(UnderpostRepository.API, 'isRemoteRepo').mockReturnValue(true);
|
|
400
|
+
for (const repository of ['', ' ', undefined, null]) {
|
|
401
|
+
const result = UnderpostRepository.API.provisionSiteRoot({
|
|
402
|
+
host: 'www.example.com',
|
|
403
|
+
siteRoot: '/home/dd/netlify_example',
|
|
404
|
+
repository,
|
|
405
|
+
});
|
|
406
|
+
expect(result).to.deep.equal({ accessible: false, cloned: false });
|
|
407
|
+
}
|
|
408
|
+
// The remote was never consulted: an empty reference is a conf fault, not a GitHub one.
|
|
409
|
+
expect(isRemote.mock.calls.length).to.equal(0);
|
|
410
|
+
expect(commands).to.deep.equal([]);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it('reports an unreachable remote without touching the document root', () => {
|
|
414
|
+
vi.spyOn(UnderpostRepository.API, 'isRemoteRepo').mockReturnValue(false);
|
|
415
|
+
const existsSync = vi.spyOn(fs, 'existsSync').mockReturnValue(false);
|
|
416
|
+
expect(
|
|
417
|
+
UnderpostRepository.API.provisionSiteRoot({
|
|
418
|
+
host: 'www.example.com',
|
|
419
|
+
siteRoot: '/home/dd/netlify_example',
|
|
420
|
+
repository: 'owner/netlify_example',
|
|
421
|
+
}),
|
|
422
|
+
).to.deep.equal({ accessible: false, cloned: false });
|
|
423
|
+
expect(commands.some((command) => command.includes('git clone'))).to.equal(false);
|
|
424
|
+
existsSync.mockRestore();
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it('treats an existing checkout as provisioned and leaves it alone', () => {
|
|
428
|
+
vi.spyOn(UnderpostRepository.API, 'isRemoteRepo').mockReturnValue(true);
|
|
429
|
+
vi.spyOn(fs, 'existsSync').mockImplementation((target) => `${target}` === '/home/dd/netlify_example/.git');
|
|
430
|
+
expect(
|
|
431
|
+
UnderpostRepository.API.provisionSiteRoot({
|
|
432
|
+
host: 'www.example.com',
|
|
433
|
+
siteRoot: '/home/dd/netlify_example',
|
|
434
|
+
repository: 'owner/netlify_example',
|
|
435
|
+
}),
|
|
436
|
+
).to.deep.equal({ accessible: true, cloned: false });
|
|
437
|
+
expect(commands).to.deep.equal([]);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// The runtime image ships the document-root directories. Reading their existence as
|
|
441
|
+
// "provisioned" skipped the clone on every fresh pod and left Apache serving 403 from a
|
|
442
|
+
// directory nothing would ever populate.
|
|
443
|
+
it('provisions a document root the image shipped but never populated', () => {
|
|
444
|
+
vi.spyOn(UnderpostRepository.API, 'isRemoteRepo').mockReturnValue(true);
|
|
445
|
+
vi.spyOn(fs, 'existsSync').mockImplementation((target) => `${target}` === '/home/dd/netlify_example');
|
|
446
|
+
vi.spyOn(fs, 'mkdirSync').mockImplementation(() => undefined);
|
|
447
|
+
expect(
|
|
448
|
+
UnderpostRepository.API.provisionSiteRoot({
|
|
449
|
+
host: 'www.example.com',
|
|
450
|
+
siteRoot: '/home/dd/netlify_example',
|
|
451
|
+
repository: 'owner/netlify_example',
|
|
452
|
+
}),
|
|
453
|
+
).to.deep.equal({ accessible: true, cloned: true });
|
|
454
|
+
expect(commands.some((command) => command.includes('git clone'))).to.equal(true);
|
|
455
|
+
// Copied in, not renamed over: the path can be image-provided or a mount point, and a
|
|
456
|
+
// rename onto one fails where a copy succeeds.
|
|
457
|
+
expect(commands).to.include('sudo cp -a "/home/dd/netlify_example.tmp/." "/home/dd/netlify_example/"');
|
|
458
|
+
expect(commands.some((command) => command.startsWith('sudo mv'))).to.equal(false);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
it('renames the clone into place when the document root does not exist at all', () => {
|
|
462
|
+
vi.spyOn(UnderpostRepository.API, 'isRemoteRepo').mockReturnValue(true);
|
|
463
|
+
vi.spyOn(fs, 'existsSync').mockReturnValue(false);
|
|
464
|
+
vi.spyOn(fs, 'mkdirSync').mockImplementation(() => undefined);
|
|
465
|
+
expect(
|
|
466
|
+
UnderpostRepository.API.provisionSiteRoot({
|
|
467
|
+
host: 'www.example.com',
|
|
468
|
+
siteRoot: '/home/dd/netlify_example',
|
|
469
|
+
repository: 'owner/netlify_example',
|
|
470
|
+
}),
|
|
471
|
+
).to.deep.equal({ accessible: true, cloned: true });
|
|
472
|
+
expect(commands).to.include('sudo mv "/home/dd/netlify_example.tmp" "/home/dd/netlify_example"');
|
|
473
|
+
});
|
|
474
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
import { vi } from 'vitest';
|
|
5
|
+
import Underpost from '../../src/index.js';
|
|
6
|
+
|
|
7
|
+
describe('SSH command output redaction', () => {
|
|
8
|
+
afterEach(() => vi.restoreAllMocks());
|
|
9
|
+
|
|
10
|
+
it('filters child output before writing it to the terminal', async () => {
|
|
11
|
+
const token = 'opaque-remote-credential_123';
|
|
12
|
+
const url = `https\\://x-access-token\\:${token}\\@github.com\\/owner\\/repo`;
|
|
13
|
+
let written = '';
|
|
14
|
+
vi.spyOn(process.stdout, 'write').mockImplementation((chunk) => {
|
|
15
|
+
written += `${chunk}`;
|
|
16
|
+
return true;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const output = await Underpost.ssh.sshRemoteRunner(`printf '%s' '${url}'`, {
|
|
20
|
+
remote: false,
|
|
21
|
+
cd: '',
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(output).to.include(token);
|
|
25
|
+
expect(written).to.not.include(token);
|
|
26
|
+
expect(written).to.include('***');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module start-options.test
|
|
5
|
+
* @description Covers the option contract of `underpost start`: every flag the command
|
|
6
|
+
* registers must be a key the callback receives, since the pod's whole bootstrap is one
|
|
7
|
+
* invocation of it.
|
|
8
|
+
*
|
|
9
|
+
* Uses 'chai' for assertions.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { expect } from 'chai';
|
|
13
|
+
import fs from 'fs-extra';
|
|
14
|
+
import { program } from '../../src/cli/index.js';
|
|
15
|
+
|
|
16
|
+
const startCommand = () => program.commands.find((command) => command.name() === 'start');
|
|
17
|
+
const camelCase = (flag) => flag.replace(/^--/, '').replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
18
|
+
|
|
19
|
+
describe('start receives every flag its command registers', () => {
|
|
20
|
+
const source = fs.readFileSync(new URL('../../src/server/runtime/start.js', import.meta.url), 'utf8');
|
|
21
|
+
const contract = source.slice(source.indexOf('async callback('), source.indexOf('Underpost.host.load'));
|
|
22
|
+
const buildStart = source.indexOf('async build(');
|
|
23
|
+
const buildContract = source.slice(buildStart, source.indexOf('async run(', buildStart));
|
|
24
|
+
|
|
25
|
+
it('names each registered flag in the callback options', () => {
|
|
26
|
+
// Regression: `--private-test-repo` selects the repository the base pull clones, and the
|
|
27
|
+
// callback's option contract never named it — the flag reached a default that dropped it.
|
|
28
|
+
for (const { long } of startCommand().options) expect(contract, long).to.include(`${camelCase(long)}:`);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('gives build its own switch per source it can pull', () => {
|
|
32
|
+
for (const flag of ['--skip-pull-repo-base', '--skip-pull-private-repo'])
|
|
33
|
+
expect(buildContract, flag).to.include(`${camelCase(flag)}:`);
|
|
34
|
+
expect(buildContract).to.include('if (options.skipPullRepoBase !== true) Underpost.start.pullRepoBase(');
|
|
35
|
+
expect(buildContract).to.include('if (options.skipPullPrivateRepo !== true)');
|
|
36
|
+
expect(buildContract).to.include('Underpost.repo.privateEngineRepoFactory(deployId,');
|
|
37
|
+
expect(buildContract).to.include('{ force: Underpost.state.isInsideContainer() }');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('runs the container in one phase, with no re-entry through the global CLI', () => {
|
|
41
|
+
// The pod's own bootstrap replaces the checkout and links the CLI before `start` is
|
|
42
|
+
// invoked, so re-execing `underpost start` here only pulled and installed a second time.
|
|
43
|
+
expect(source).to.not.include('startFlagsFactory');
|
|
44
|
+
expect(source).to.not.match(/shellExec\(`underpost start /);
|
|
45
|
+
});
|
|
46
|
+
});
|