@underpostnet/cyberia 3.3.0 → 3.3.76
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 +17 -5
- package/.github/workflows/coverall.cyberia.ci.yml +39 -14
- package/.github/workflows/cyberia-client.cd.yml +5 -0
- package/.github/workflows/cyberia-server.cd.yml +5 -0
- 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 +3 -0
- package/.github/workflows/engine-cyberia.ci.yml +4 -5
- package/.github/workflows/ghpkg.ci.yml +35 -20
- package/.github/workflows/hardhat.ci.yml +12 -11
- package/.github/workflows/npmpkg.ci.yml +17 -15
- package/.github/workflows/publish.cyberia.ci.yml +44 -0
- package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
- package/.github/workflows/release.cd.yml +1 -0
- package/.prettierignore +1 -0
- package/AGENTS.md +96 -0
- package/CHANGELOG.md +653 -2513
- package/CLI-HELP.md +323 -157
- package/Dockerfile +25 -9
- package/Dockerfile.dev +25 -9
- package/Dockerfile.test +5 -5
- package/README.md +48 -28
- package/bin/build.js +86 -41
- package/bin/build.template.js +8 -3
- package/bin/cyberia.js +1494 -1403
- package/bin/deploy.js +18 -104
- package/bin/index.js +1494 -1403
- package/compose.env +17 -5
- package/conf.js +98 -7
- package/deploy/cyberia-client/deploy.sh +46 -0
- package/deploy/cyberia-client/package.sh +17 -0
- package/deploy/cyberia-client/state.sh +15 -0
- package/deploy/cyberia-server/deploy.sh +46 -0
- package/deploy/cyberia-server/package.sh +17 -0
- package/deploy/cyberia-server/state.sh +15 -0
- package/deploy/dd-cyberia/deploy.sh +9 -29
- package/deploy/dd-cyberia/init.sh +38 -45
- package/deploy/dd-cyberia/package.sh +16 -0
- package/deploy/dd-cyberia/state.sh +14 -0
- package/deploy/dd-cyberia/sync-deploy.sh +133 -147
- package/deploy/lib/config.sh +29 -0
- package/deploy/lib/github-actions-logging.sh +610 -0
- package/deploy/lib/host.sh +194 -0
- package/deploy/lib/state.sh +65 -0
- package/deploy/pwa-microservices-template/deploy.sh +17 -42
- package/deploy/release/deploy.sh +9 -41
- package/deployment.yaml +7 -2
- package/docker-compose.yml +23 -17
- 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 +101 -40
- package/hardhat/package.json +2 -2
- package/manifests/alertmanager/deployment.yaml +81 -0
- package/manifests/blackbox-exporter/deployment.yaml +75 -0
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +32 -7
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +32 -7
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/mongo-express/deployment.yaml +46 -27
- package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
- package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
- package/manifests/deployment/mongo-express/service.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
- 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 +87 -12
- package/scripts/event-monitor.sh +56 -0
- package/scripts/k3s-node-setup.sh +27 -14
- package/scripts/kubeadm-node-setup.sh +31 -11
- package/scripts/maas-setup.sh +8 -8
- package/scripts/selinux-normalize.sh +907 -0
- package/scripts/shutdown-machine.sh +843 -0
- package/scripts/test-monitor.sh +5 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +15 -10
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +7 -2
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +90 -186
- 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 +3 -3
- package/src/api/cyberia-action/cyberia-action.service.js +5 -6
- package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
- package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
- package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
- package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +2 -4
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +13 -35
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +17 -34
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +2 -2
- 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.model.js +2 -0
- package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.service.js +3 -3
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +17 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +468 -5
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +502 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +29 -40
- package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
- package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +35 -142
- package/src/api/cyberia-instance/cyberia-instance.controller.js +2 -5
- package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
- package/src/api/cyberia-instance/cyberia-instance.router.js +5 -18
- package/src/api/cyberia-instance/cyberia-instance.service.js +5 -45
- package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +76 -3
- 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 +8 -4
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
- package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.router.js +4 -4
- package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.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 +403 -214
- package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
- package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
- 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.ref.js +153 -0
- package/src/api/file/file.ref.json +11 -2
- 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 +47 -12
- package/src/api/object-layer/object-layer.router.js +12 -5
- package/src/api/object-layer/object-layer.service.js +116 -123
- 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 +402 -0
- package/src/cli/baremetal.js +30 -35
- package/src/cli/client.js +306 -0
- package/src/cli/cloud-init.js +3 -3
- package/src/cli/cluster.js +191 -82
- package/src/cli/db.js +120 -68
- package/src/cli/deploy.js +157 -75
- 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-selection.js +115 -0
- package/src/cli/fs.js +159 -343
- package/src/cli/host.js +672 -0
- package/src/cli/image.js +4 -6
- package/src/cli/index.js +343 -151
- 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 +16 -12
- package/src/cli/repository.js +586 -363
- package/src/cli/run.js +398 -843
- package/src/cli/secrets.js +2158 -964
- package/src/cli/ssh.js +478 -279
- package/src/cli/state.js +394 -0
- package/src/cli/static.js +2 -2
- package/src/cli/system.js +1 -1
- package/src/cli/test.js +203 -125
- package/src/cli/vultr.js +61 -21
- package/src/cli/wireguard.js +1112 -306
- package/src/client/components/core/CalendarCore.js +53 -96
- package/src/client/components/core/Docs.js +327 -303
- package/src/client/components/core/FileExplorer.js +0 -21
- package/src/client/components/core/Modal.js +56 -1
- 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/ActionEngineCyberia.js +12 -36
- package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
- package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
- package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
- package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
- package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +2 -35
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
- package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
- 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 +15 -15
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +313 -30
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
- package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
- package/src/client/public/cyberia-docs/CYBERIA.md +48 -28
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
- 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/STATS-PROGRESSION.md +217 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
- 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-audio/cyberia-audio.service.js +99 -0
- package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
- package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
- package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
- package/src/client/services/object-layer/object-layer.management.js +6 -10
- package/src/client/services/object-layer/object-layer.service.js +3 -1
- 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 +92 -77
- package/src/client-builder/client-build-live.js +2 -2
- package/src/client-builder/client-build.js +105 -74
- package/src/client-builder/client-bundle.js +347 -0
- 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/MongoExpress.js +187 -0
- package/src/db/mongo/MongooseDB.js +7 -8
- package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
- package/src/grpc/cyberia/grpc-server.js +6 -8
- package/src/index.js +79 -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 +144 -147
- package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
- package/src/projects/cyberia/besu-genesis-generator.js +8 -17
- package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
- package/src/projects/cyberia/catalog-cyberia.js +54 -10
- package/src/projects/cyberia/gemini-client.js +4 -4
- package/src/projects/cyberia/generate-saga.js +5 -12
- package/src/projects/cyberia/hot-reload-trigger.js +18 -29
- package/src/projects/cyberia/instance-backup.js +210 -0
- package/src/projects/cyberia/instance-data.js +178 -258
- package/src/projects/cyberia/ipfs-client.js +4 -4
- package/src/projects/cyberia/map-preview-generator.js +33 -69
- package/src/projects/cyberia/object-layer.js +153 -320
- package/src/projects/cyberia/seed-audio.js +139 -0
- package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
- package/src/projects/cyberia/semantic-layer-generator.js +3 -19
- package/src/projects/cyberia/stat-balance.js +81 -0
- package/src/projects/cyberia/stat-commands.js +23 -0
- package/src/projects/cyberia/stat-contract-generator.js +101 -0
- package/src/projects/underpost/catalog-underpost.js +9 -1
- package/src/proxy.js +4 -7
- package/src/runtime/cyberia-client/Dockerfile +17 -8
- package/src/runtime/cyberia-client/Dockerfile.dev +13 -4
- package/src/runtime/cyberia-server/Dockerfile +18 -6
- package/src/runtime/cyberia-server/Dockerfile.dev +16 -3
- package/src/runtime/engine-cyberia/Dockerfile +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.test +5 -5
- package/src/runtime/engine-cyberia/compose.env +17 -5
- package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
- 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 +188 -0
- package/src/server/build/execution.js +402 -0
- package/src/server/build/package.js +508 -0
- package/src/server/build/testing.js +578 -0
- package/src/server/{dns.js → network/dns.js} +144 -11
- package/src/server/{forward-proxy.js → network/forward-proxy.js} +10 -18
- package/src/server/{middlewares.js → network/middlewares.js} +11 -5
- 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/{underpost-compression.js → network/underpost-compression.js} +1 -1
- package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +7 -7
- package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +2 -2
- package/src/server/{cri.js → ops/cri.js} +2 -2
- package/src/server/{cron.js → ops/cron.js} +349 -74
- package/src/server/ops/event-notification.js +284 -0
- package/src/server/{logger.js → ops/logger.js} +143 -23
- package/src/server/ops/monitoring.js +1724 -0
- package/src/server/{systemd.js → ops/systemd.js} +55 -1
- package/src/server/{conf.js → runtime/conf.js} +516 -423
- 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 -12
- 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/{selinux.js → security/selinux.js} +1 -1
- package/src/server/{backup.js → storage/backup.js} +17 -8
- package/src/server/{data-query.js → storage/data-query.js} +17 -1
- package/src/server/storage/downloader.js +121 -0
- package/src/server/storage/repository.js +68 -0
- package/src/server/storage/zip.js +153 -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/atlas-sprite-sheet-store.test.js +402 -0
- package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
- package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +64 -0
- package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
- package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
- package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +17 -23
- package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
- package/test/integration/app/cyberia/cyberia-load.test.js +466 -0
- package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
- package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
- package/test/integration/app/cyberia/fallback-world-capture.test.js +338 -0
- package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
- package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
- package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
- package/test/integration/app/cyberia/seed-audio.test.js +275 -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/{selinux.test.js → integration/infra/1-security/selinux.test.js} +2 -4
- 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 +1187 -0
- package/test/{wireguard-edge.test.js → integration/infra/2-network/wireguard-edge.test.js} +649 -55
- 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/3-cluster/mongo-express-deploy.test.js +156 -0
- package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -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} +6 -6
- package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +4 -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 +361 -0
- package/test/unit/client-bundle.test.js +313 -0
- package/test/unit/conf-loading.test.js +303 -0
- package/test/unit/conf-resolution.test.js +996 -0
- package/test/unit/coverage-artifact.test.js +221 -0
- package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
- package/test/unit/cyberia/instance-backup.test.js +183 -0
- package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
- package/test/unit/cyberia/publish-workflow.test.js +22 -0
- package/test/unit/cyberia/stat-balance.test.js +69 -0
- package/test/unit/deploy-env-resolution.test.js +38 -0
- package/test/unit/deploy-log-table.test.js +518 -0
- package/test/unit/downloader-integrity.test.js +98 -0
- package/test/unit/execution-profiles.test.js +219 -0
- package/test/unit/file-reference-registry.test.js +141 -0
- package/test/unit/fleet-sync-source.test.js +149 -0
- package/test/unit/fs-storage-paths.test.js +596 -0
- package/test/unit/logger-redaction.test.js +141 -0
- package/test/unit/package.test.js +457 -0
- package/test/unit/prepare-host.test.js +382 -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 +220 -0
- package/test/unit/zip-archive.test.js +142 -0
- package/vitest.config.js +66 -0
- package/.nycrc +0 -9
- package/deploy/lib/logging.sh +0 -96
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
- package/manifests/mongodb/pv-pvc.yaml +0 -59
- package/scripts/coverall-test-cyberia.sh +0 -24
- package/scripts/coverall-test.sh +0 -24
- package/scripts/link-local-underpost-cli.sh +0 -6
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
- 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/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
- 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/downloader.js +0 -73
- package/src/server/environment.js +0 -98
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
import {
|
|
5
|
+
activeExecutionProfile,
|
|
6
|
+
CAPABILITIES,
|
|
7
|
+
classifyCommand,
|
|
8
|
+
cli,
|
|
9
|
+
EXECUTION_PROFILE_ENV_KEY,
|
|
10
|
+
EXECUTION_PROFILES,
|
|
11
|
+
executionDecisionFactory,
|
|
12
|
+
executionProfileFactory,
|
|
13
|
+
profileFromOptionsFactory,
|
|
14
|
+
withExecutionProfile,
|
|
15
|
+
} from '../../src/server/build/execution.js';
|
|
16
|
+
|
|
17
|
+
describe('command capability classification', () => {
|
|
18
|
+
it('separates cluster reads from cluster writes', () => {
|
|
19
|
+
expect(classifyCommand('kubectl get pods')).to.equal('cluster:read');
|
|
20
|
+
expect(classifyCommand('kubectl describe svc x -n default')).to.equal('cluster:read');
|
|
21
|
+
expect(classifyCommand('kubectl apply -f manifest.yaml')).to.equal('cluster:write');
|
|
22
|
+
expect(classifyCommand('kubectl delete secret underpost-config -n default')).to.equal('cluster:write');
|
|
23
|
+
expect(classifyCommand('kubectl exec pod -- sh -c ls')).to.equal('cluster:write');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('finds the verb past kubectl flags that consume their next token', () => {
|
|
27
|
+
expect(classifyCommand('kubectl -n default get pods')).to.equal('cluster:read');
|
|
28
|
+
expect(classifyCommand('kubectl --namespace default --context x get svc')).to.equal('cluster:read');
|
|
29
|
+
expect(classifyCommand('kubectl -n default apply -f x.yaml')).to.equal('cluster:write');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('treats an unrecognised kubectl verb as a write rather than assuming it is harmless', () => {
|
|
33
|
+
expect(classifyCommand('kubectl some-future-verb thing')).to.equal('cluster:write');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('classifies through sudo rather than stopping at it', () => {
|
|
37
|
+
expect(classifyCommand('sudo kubectl apply -f x.yaml')).to.equal('cluster:write');
|
|
38
|
+
expect(classifyCommand('sudo kubectl get pods')).to.equal('cluster:read');
|
|
39
|
+
expect(classifyCommand('sudo -u dd kubectl get pods')).to.equal('cluster:read');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('treats an escalated unknown command as a host mutation', () => {
|
|
43
|
+
expect(classifyCommand('sudo some-vendor-tool --install')).to.equal('host:write');
|
|
44
|
+
expect(classifyCommand('some-vendor-tool --install')).to.equal('fs');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('takes the most privileged segment of a compound command', () => {
|
|
48
|
+
expect(classifyCommand('kubectl create secret generic x --dry-run=client -o yaml | kubectl apply -f -')).to.equal(
|
|
49
|
+
'cluster:write',
|
|
50
|
+
);
|
|
51
|
+
expect(classifyCommand('cd /home/dd && git add . && kubectl apply -f x.yaml')).to.equal('cluster:write');
|
|
52
|
+
expect(classifyCommand('cd /home/dd/cyberia-instances && git status')).to.equal('git');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('reads a heredoc as data, not as a pipeline', () => {
|
|
56
|
+
const cmd = ["kubectl apply -f - -n default <<'EOF'", 'apiVersion: v1', 'kind: Secret', 'EOF'].join('\n');
|
|
57
|
+
expect(classifyCommand(cmd)).to.equal('cluster:write');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('classifies host, network and git work distinctly', () => {
|
|
61
|
+
expect(classifyCommand('sudo dnf install -y cockpit')).to.equal('host:write');
|
|
62
|
+
expect(classifyCommand('sudo systemctl enable --now cockpit.socket')).to.equal('host:write');
|
|
63
|
+
expect(classifyCommand('curl https://example.com')).to.equal('net');
|
|
64
|
+
expect(classifyCommand('git add .')).to.equal('git');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('lets nested engine invocations through so a profile can reach its own stages', () => {
|
|
68
|
+
expect(classifyCommand('node bin deploy --build-manifest dd development')).to.equal('fs');
|
|
69
|
+
expect(classifyCommand('cd /x && underpost pull . underpostnet/cyberia-instances')).to.equal('fs');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('never returns a capability outside the declared set', () => {
|
|
73
|
+
const commands = [
|
|
74
|
+
'',
|
|
75
|
+
' ',
|
|
76
|
+
'echo hi',
|
|
77
|
+
'NODE_ENV=production node bin client',
|
|
78
|
+
'sudo',
|
|
79
|
+
'kubectl',
|
|
80
|
+
'helm list -n default',
|
|
81
|
+
'helm upgrade --install x ./chart',
|
|
82
|
+
];
|
|
83
|
+
for (const cmd of commands) expect(CAPABILITIES).to.include(classifyCommand(cmd));
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('execution profiles', () => {
|
|
88
|
+
it('permits everything under LIVE_CLUSTER', () => {
|
|
89
|
+
for (const capability of CAPABILITIES) expect(EXECUTION_PROFILES.LIVE_CLUSTER.permits).to.include(capability);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('permits build outputs but no environment mutation under HERMETIC_BUILD', () => {
|
|
93
|
+
const { permits } = EXECUTION_PROFILES.HERMETIC_BUILD;
|
|
94
|
+
expect(permits).to.have.members(['fs', 'git']);
|
|
95
|
+
for (const denied of ['cluster:read', 'cluster:write', 'host:write', 'net']) expect(permits).to.not.include(denied);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('permits nothing under OFFLINE_DRY_RUN', () => {
|
|
99
|
+
expect(EXECUTION_PROFILES.OFFLINE_DRY_RUN.permits).to.deep.equal([]);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('falls back to the default profile rather than throwing on an unknown name', () => {
|
|
103
|
+
expect(executionProfileFactory('nope').name).to.equal('LIVE_CLUSTER');
|
|
104
|
+
expect(executionProfileFactory('').name).to.equal('LIVE_CLUSTER');
|
|
105
|
+
expect(executionProfileFactory(undefined).name).to.equal('LIVE_CLUSTER');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('accepts a profile name in either kebab or snake form', () => {
|
|
109
|
+
expect(executionProfileFactory('hermetic-build').name).to.equal('HERMETIC_BUILD');
|
|
110
|
+
expect(executionProfileFactory('hermetic_build').name).to.equal('HERMETIC_BUILD');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('execution decisions', () => {
|
|
115
|
+
it('denies cluster work under HERMETIC_BUILD and permits build output', () => {
|
|
116
|
+
const denied = executionDecisionFactory('kubectl delete secret x -n default', { profile: 'HERMETIC_BUILD' });
|
|
117
|
+
expect(denied.permitted).to.equal(false);
|
|
118
|
+
expect(denied.capability).to.equal('cluster:write');
|
|
119
|
+
expect(denied.neutral).to.equal(true);
|
|
120
|
+
expect(executionDecisionFactory('git add .', { profile: 'HERMETIC_BUILD' }).permitted).to.equal(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('permits the same command under LIVE_CLUSTER', () => {
|
|
124
|
+
expect(
|
|
125
|
+
executionDecisionFactory('kubectl delete secret x -n default', { profile: 'LIVE_CLUSTER' }).permitted,
|
|
126
|
+
).to.equal(true);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('denies even local work under OFFLINE_DRY_RUN', () => {
|
|
130
|
+
expect(executionDecisionFactory('echo hi', { profile: 'OFFLINE_DRY_RUN' }).permitted).to.equal(false);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('profile propagation', () => {
|
|
135
|
+
const originalProfile = process.env[EXECUTION_PROFILE_ENV_KEY];
|
|
136
|
+
|
|
137
|
+
afterEach(() => {
|
|
138
|
+
if (originalProfile === undefined) delete process.env[EXECUTION_PROFILE_ENV_KEY];
|
|
139
|
+
else process.env[EXECUTION_PROFILE_ENV_KEY] = originalProfile;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('exports the profile to the environment so child processes inherit it', () => {
|
|
143
|
+
withExecutionProfile('HERMETIC_BUILD', () => {
|
|
144
|
+
expect(process.env[EXECUTION_PROFILE_ENV_KEY]).to.equal('HERMETIC_BUILD');
|
|
145
|
+
expect(activeExecutionProfile().name).to.equal('HERMETIC_BUILD');
|
|
146
|
+
});
|
|
147
|
+
expect(process.env[EXECUTION_PROFILE_ENV_KEY]).to.equal(originalProfile);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('restores the previous profile when the body throws', () => {
|
|
151
|
+
expect(() =>
|
|
152
|
+
withExecutionProfile('OFFLINE_DRY_RUN', () => {
|
|
153
|
+
throw new Error('stage failed');
|
|
154
|
+
}),
|
|
155
|
+
).to.throw('stage failed');
|
|
156
|
+
expect(process.env[EXECUTION_PROFILE_ENV_KEY]).to.equal(originalProfile);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('restores the previous profile after an async body settles', async () => {
|
|
160
|
+
await withExecutionProfile('HERMETIC_BUILD', async () => {
|
|
161
|
+
expect(activeExecutionProfile().name).to.equal('HERMETIC_BUILD');
|
|
162
|
+
});
|
|
163
|
+
expect(process.env[EXECUTION_PROFILE_ENV_KEY]).to.equal(originalProfile);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('nests without leaking the inner profile outward', () => {
|
|
167
|
+
withExecutionProfile('HERMETIC_BUILD', () => {
|
|
168
|
+
withExecutionProfile('OFFLINE_DRY_RUN', () => {
|
|
169
|
+
expect(activeExecutionProfile().name).to.equal('OFFLINE_DRY_RUN');
|
|
170
|
+
});
|
|
171
|
+
expect(activeExecutionProfile().name).to.equal('HERMETIC_BUILD');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('defaults to LIVE_CLUSTER when the environment says nothing', () => {
|
|
176
|
+
delete process.env[EXECUTION_PROFILE_ENV_KEY];
|
|
177
|
+
expect(activeExecutionProfile().name).to.equal('LIVE_CLUSTER');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('legacy bypass flag aliases', () => {
|
|
182
|
+
it('prefers an explicit --profile over every alias', () => {
|
|
183
|
+
expect(profileFromOptionsFactory({ profile: 'OFFLINE_DRY_RUN', disableUpdateUnderpostConfig: true })).to.equal(
|
|
184
|
+
'OFFLINE_DRY_RUN',
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('aliases the legacy flag only in the mode where it means the same thing', () => {
|
|
189
|
+
expect(profileFromOptionsFactory({ disableUpdateUnderpostConfig: true, buildManifest: true })).to.equal(
|
|
190
|
+
'HERMETIC_BUILD',
|
|
191
|
+
);
|
|
192
|
+
// A live deploy carrying the same flag must stay live: it is a step toggle there, and
|
|
193
|
+
// silently eliding every cluster write would turn the deploy into a no-op.
|
|
194
|
+
expect(profileFromOptionsFactory({ disableUpdateUnderpostConfig: true })).to.equal('');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('selects nothing when no flag and no profile is given', () => {
|
|
198
|
+
expect(profileFromOptionsFactory({})).to.equal('');
|
|
199
|
+
expect(profileFromOptionsFactory()).to.equal('');
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('CLI resolution', () => {
|
|
204
|
+
it('resolves underpost to a runnable command', () => {
|
|
205
|
+
const resolved = cli();
|
|
206
|
+
expect(resolved === 'underpost' || /^node \/.+\/bin\/index\.js$/.test(resolved)).to.equal(true);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('re-enters this checkout under local, never a global install', () => {
|
|
210
|
+
// A globally installed underpost is a different package: resolving to it for a stage
|
|
211
|
+
// that operates on this working tree runs the wrong code against the right cwd.
|
|
212
|
+
expect(cli('underpost', { local: true })).to.match(/^node \/.+\/bin\/index\.js$/);
|
|
213
|
+
expect(cli('underpost', { local: true })).to.not.equal('underpost');
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('passes through any other binary name unchanged', () => {
|
|
217
|
+
expect(cli('kubectl')).to.equal('kubectl');
|
|
218
|
+
});
|
|
219
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module file-reference-registry.test
|
|
5
|
+
* @description Covers `src/api/file/file.ref.js`: the mapping of a model to the fields that hold
|
|
6
|
+
* a File `_id`, and the two deletions built on it. Every writer that removes a document reads
|
|
7
|
+
* this registry to take the blobs it owned with it, so what is asserted here is what keeps the
|
|
8
|
+
* File collection free of unreachable documents.
|
|
9
|
+
*
|
|
10
|
+
* Uses 'chai' for assertions.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { expect } from 'chai';
|
|
14
|
+
import {
|
|
15
|
+
deleteOwnedFiles,
|
|
16
|
+
deleteUnreferencedFiles,
|
|
17
|
+
documentFileIds,
|
|
18
|
+
fileRefApis,
|
|
19
|
+
fileRefFields,
|
|
20
|
+
} from '../../src/api/file/file.ref.js';
|
|
21
|
+
|
|
22
|
+
/** Minimal collection: the helpers only run `find(filter, projection).lean()` and `deleteMany`. */
|
|
23
|
+
const collection = (docs) => ({
|
|
24
|
+
docs,
|
|
25
|
+
find(filter) {
|
|
26
|
+
const clauses = filter.$or ?? [filter];
|
|
27
|
+
const matched = docs.filter((doc) =>
|
|
28
|
+
clauses.some((clause) =>
|
|
29
|
+
Object.entries(clause).every(([field, condition]) => {
|
|
30
|
+
const value = doc[field];
|
|
31
|
+
if (value === undefined || value === null) return false;
|
|
32
|
+
return condition.$in.map(String).includes(String(value));
|
|
33
|
+
}),
|
|
34
|
+
),
|
|
35
|
+
);
|
|
36
|
+
return { lean: async () => matched };
|
|
37
|
+
},
|
|
38
|
+
async deleteMany({ _id: { $in } }) {
|
|
39
|
+
const removing = new Set($in.map(String));
|
|
40
|
+
const before = docs.length;
|
|
41
|
+
this.docs = docs = docs.filter((doc) => !removing.has(String(doc._id)));
|
|
42
|
+
return { deletedCount: before - docs.length };
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('the File reference registry', () => {
|
|
47
|
+
it('answers the fields of a registered api and nothing for an unregistered one', () => {
|
|
48
|
+
expect(fileRefFields('atlas-sprite-sheet')).to.deep.equal(['fileId', 'minifyFileId', 'idlePreviewFileId']);
|
|
49
|
+
expect(fileRefFields('cyberia-map')).to.deep.equal(['thumbnail', 'preview']);
|
|
50
|
+
expect(fileRefFields('object-layer')).to.deep.equal([]);
|
|
51
|
+
expect(fileRefApis()).to.include('cyberia-audio');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('reads ids out of documents by field, skipping the ones that hold none', () => {
|
|
55
|
+
const docs = [{ fileId: 'a', minifyFileId: 'b' }, { fileId: 'a' }, { minifyFileId: null }];
|
|
56
|
+
expect(documentFileIds(docs, ['fileId', 'minifyFileId'])).to.deep.equal(['a', 'b']);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe('deleting the files a collection owned', () => {
|
|
61
|
+
it('removes the ids no surviving document holds', async () => {
|
|
62
|
+
const files = collection([{ _id: 'atlas-1' }, { _id: 'minify-1' }, { _id: 'unrelated' }]);
|
|
63
|
+
const atlases = collection([]);
|
|
64
|
+
|
|
65
|
+
const removed = await deleteOwnedFiles({
|
|
66
|
+
File: files,
|
|
67
|
+
Owner: atlases,
|
|
68
|
+
fields: ['fileId', 'minifyFileId'],
|
|
69
|
+
ids: ['atlas-1', 'minify-1'],
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(removed).to.equal(2);
|
|
73
|
+
expect(files.docs.map((doc) => doc._id)).to.deep.equal(['unrelated']);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('keeps an id a survivor still points at', async () => {
|
|
77
|
+
// Renders are content addressed, so a duplicate document of the same item resolves to the
|
|
78
|
+
// same File id. Dropping the duplicate must not blind the document that remains.
|
|
79
|
+
const files = collection([{ _id: 'shared' }, { _id: 'gone' }]);
|
|
80
|
+
const atlases = collection([{ _id: 'survivor', fileId: 'shared', minifyFileId: null }]);
|
|
81
|
+
|
|
82
|
+
const removed = await deleteOwnedFiles({
|
|
83
|
+
File: files,
|
|
84
|
+
Owner: atlases,
|
|
85
|
+
fields: ['fileId', 'minifyFileId'],
|
|
86
|
+
ids: ['shared', 'gone'],
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(removed).to.equal(1);
|
|
90
|
+
expect(files.docs.map((doc) => doc._id)).to.deep.equal(['shared']);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('deletes nothing when handed no candidates', async () => {
|
|
94
|
+
const files = collection([{ _id: 'kept' }]);
|
|
95
|
+
expect(await deleteOwnedFiles({ File: files, Owner: collection([]), fields: ['fileId'], ids: [] })).to.equal(0);
|
|
96
|
+
expect(files.docs).to.have.lengthOf(1);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('sweeping files no registered model references', () => {
|
|
101
|
+
const loadedModels = (overrides = {}) => {
|
|
102
|
+
const models = Object.fromEntries(fileRefApis().map((api) => [api, collection([])]));
|
|
103
|
+
return { ...models, ...overrides };
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
it('refuses to delete while a registered api has no model to read', async () => {
|
|
107
|
+
// An unreadable collection cannot be shown to hold no reference, and a sweep that assumed
|
|
108
|
+
// otherwise would delete a live blob belonging to another domain.
|
|
109
|
+
const files = collection([{ _id: 'candidate' }]);
|
|
110
|
+
const models = loadedModels();
|
|
111
|
+
delete models.document;
|
|
112
|
+
|
|
113
|
+
const result = await deleteUnreferencedFiles({
|
|
114
|
+
File: files,
|
|
115
|
+
ids: ['candidate'],
|
|
116
|
+
getModel: (api) => {
|
|
117
|
+
if (!models[api]) throw new Error(`Model not loaded: ${api}`);
|
|
118
|
+
return models[api];
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(result.skipped).to.equal('document');
|
|
123
|
+
expect(result.removed).to.equal(0);
|
|
124
|
+
expect(files.docs).to.have.lengthOf(1);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('deletes only the candidates every model agrees it never references', async () => {
|
|
128
|
+
const files = collection([{ _id: 'orphan' }, { _id: 'held' }]);
|
|
129
|
+
const models = loadedModels({ 'cyberia-map': collection([{ _id: 'map', thumbnail: 'held', preview: null }]) });
|
|
130
|
+
|
|
131
|
+
const result = await deleteUnreferencedFiles({
|
|
132
|
+
File: files,
|
|
133
|
+
ids: ['orphan', 'held'],
|
|
134
|
+
getModel: (api) => models[api],
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(result.skipped).to.equal('');
|
|
138
|
+
expect(result.removed).to.equal(1);
|
|
139
|
+
expect(files.docs.map((doc) => doc._id)).to.deep.equal(['held']);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
import Underpost from '../../src/index.js';
|
|
5
|
+
import { hostAddressesFactory } from '../../src/cli/wireguard.js';
|
|
6
|
+
|
|
7
|
+
const syncPrivateConfMock = vi.hoisted(() => vi.fn());
|
|
8
|
+
vi.mock('../../src/server/runtime/conf.js', async (importOriginal) => ({
|
|
9
|
+
...(await importOriginal()),
|
|
10
|
+
syncPrivateConf: syncPrivateConfMock,
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
describe('a fleet command cannot fall back to local execution', () => {
|
|
14
|
+
it('refuses when a remote target resolved no SSH identity', async () => {
|
|
15
|
+
let thrown;
|
|
16
|
+
try {
|
|
17
|
+
await Underpost.event.runCommand('echo should-not-run', { requireRemote: true, host: '10.0.0.9' });
|
|
18
|
+
} catch (error) {
|
|
19
|
+
thrown = error;
|
|
20
|
+
}
|
|
21
|
+
expect(thrown, 'runCommand should have thrown').to.be.an('error');
|
|
22
|
+
expect(thrown.message).to.include('refusing to run locally');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('still runs locally for remediation, which has no such requirement', async () => {
|
|
26
|
+
const result = await Underpost.event.runCommand('echo local-remediation-ok', { silent: true });
|
|
27
|
+
expect(result.ok).to.equal(true);
|
|
28
|
+
expect(`${result.output}`).to.include('local-remediation-ok');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('runs locally from where it is, when the deploy path is not on this machine', async () => {
|
|
32
|
+
// A CI container checks the engine out under /__w/<repo>, so entering the deploy path is
|
|
33
|
+
// impossible there; that chdir failing reported a perfectly runnable command as a failed
|
|
34
|
+
// remediation.
|
|
35
|
+
const output = await Underpost.ssh.sshRemoteRunner('echo local-remediation-ok', {
|
|
36
|
+
cd: '/underpost/absent-deploy-path',
|
|
37
|
+
remote: false,
|
|
38
|
+
silent: true,
|
|
39
|
+
});
|
|
40
|
+
expect(`${output}`).to.include('local-remediation-ok');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('wireguard sync never switches the checkout it runs from', () => {
|
|
45
|
+
const originalTargets = Underpost.wireguard.syncTargets;
|
|
46
|
+
const originalRunCommand = Underpost.event.runCommand;
|
|
47
|
+
const originalGetDefaultBranch = Underpost.repo.getDefaultBranch;
|
|
48
|
+
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
Underpost.wireguard.syncTargets = originalTargets;
|
|
51
|
+
Underpost.event.runCommand = originalRunCommand;
|
|
52
|
+
Underpost.repo.getDefaultBranch = originalGetDefaultBranch;
|
|
53
|
+
syncPrivateConfMock.mockReset();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const stub = (targets) => {
|
|
57
|
+
const dispatched = [];
|
|
58
|
+
Underpost.wireguard.syncTargets = () => targets;
|
|
59
|
+
Underpost.event.runCommand = async (command, options) => {
|
|
60
|
+
dispatched.push({ host: options.host, requireRemote: options.requireRemote });
|
|
61
|
+
return { ok: true, output: '' };
|
|
62
|
+
};
|
|
63
|
+
return dispatched;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Dispatch fixtures use RFC 5737 documentation addresses on purpose: the guard skips any node
|
|
67
|
+
// registered at an address this machine holds, so a fixture that names a real fleet address —
|
|
68
|
+
// the control plane's LAN address, or its 10.0.0.x tunnel address — stops being a remote node
|
|
69
|
+
// on the very hosts the suite runs on.
|
|
70
|
+
const remote = { nodeName: 'vultr', user: 'root', host: '203.0.113.10', via: 'root@203.0.113.10:22' };
|
|
71
|
+
|
|
72
|
+
it('skips a node registered at an address this machine holds', async () => {
|
|
73
|
+
// The peer list is keyed by managementHost because it is unique; a hostname is not, and
|
|
74
|
+
// the control plane and this workstation are both `localhost.localdomain`.
|
|
75
|
+
const [ownAddress] = [...hostAddressesFactory()];
|
|
76
|
+
expect(ownAddress, 'this host must have a routable address to exercise the guard').to.be.a('string');
|
|
77
|
+
const self = { nodeName: 'control', user: 'admin', host: ownAddress, via: 'ssh' };
|
|
78
|
+
const dispatched = stub([self, remote]);
|
|
79
|
+
|
|
80
|
+
await Underpost.wireguard.sync({ cmd: 'echo fleet' });
|
|
81
|
+
|
|
82
|
+
expect(dispatched.map(({ host }) => host)).to.deep.equal(['203.0.113.10']);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('skips a target that resolved to local execution', async () => {
|
|
86
|
+
const local = { nodeName: 'control', user: '', host: '', via: 'local' };
|
|
87
|
+
const dispatched = stub([local, remote]);
|
|
88
|
+
|
|
89
|
+
await Underpost.wireguard.sync({ cmd: 'echo fleet' });
|
|
90
|
+
|
|
91
|
+
expect(dispatched).to.have.lengthOf(1);
|
|
92
|
+
expect(dispatched[0].host).to.equal('203.0.113.10');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('marks every dispatch remote-only', async () => {
|
|
96
|
+
const dispatched = stub([remote]);
|
|
97
|
+
await Underpost.wireguard.sync({ cmd: 'echo fleet' });
|
|
98
|
+
expect(dispatched.every(({ requireRemote }) => requireRemote === true)).to.equal(true);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('fails instead of reporting success when every node is this machine', async () => {
|
|
102
|
+
stub([{ nodeName: 'control', user: '', host: '', via: 'local' }]);
|
|
103
|
+
let thrown;
|
|
104
|
+
try {
|
|
105
|
+
await Underpost.wireguard.sync({ cmd: 'echo fleet' });
|
|
106
|
+
} catch (error) {
|
|
107
|
+
thrown = error;
|
|
108
|
+
}
|
|
109
|
+
expect(thrown, 'an all-local selection must not look like a successful sync').to.be.an('error');
|
|
110
|
+
expect(thrown.message).to.include('sync source');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('still syncs a remote node that merely shares this machine hostname', async () => {
|
|
114
|
+
// The reported case: the control plane and this workstation are both
|
|
115
|
+
// `localhost.localdomain`, so the remote one must still be reached, not skipped.
|
|
116
|
+
const sameName = { nodeName: 'localhost.localdomain', user: 'admin', host: '198.51.100.85', via: 'ssh' };
|
|
117
|
+
const dispatched = stub([sameName]);
|
|
118
|
+
await Underpost.wireguard.sync({ cmd: 'echo fleet' });
|
|
119
|
+
expect(dispatched.map(({ host }) => host)).to.deep.equal(['198.51.100.85']);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('publishes an associated deploy private repo before updating remote nodes', async () => {
|
|
123
|
+
const order = [];
|
|
124
|
+
Underpost.repo.getDefaultBranch = () => 'main';
|
|
125
|
+
Underpost.wireguard.syncTargets = () => [remote];
|
|
126
|
+
syncPrivateConfMock.mockImplementation((deployId) => order.push(`publish:${deployId}`));
|
|
127
|
+
Underpost.event.runCommand = async () => {
|
|
128
|
+
order.push('update');
|
|
129
|
+
return { ok: true, output: '' };
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
await Underpost.wireguard.sync({ repoEngine: 'fixture-org/engine-test-cyberia' });
|
|
133
|
+
|
|
134
|
+
expect(order).to.deep.equal(['publish:dd-cyberia', 'update']);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('does not publish a deploy private repo for the base engine, a custom command, or a dry run', async () => {
|
|
138
|
+
const published = [];
|
|
139
|
+
Underpost.repo.getDefaultBranch = () => 'main';
|
|
140
|
+
syncPrivateConfMock.mockImplementation((deployId) => published.push(deployId));
|
|
141
|
+
stub([remote]);
|
|
142
|
+
|
|
143
|
+
await Underpost.wireguard.sync({ repoEngine: 'fixture-org/engine' });
|
|
144
|
+
await Underpost.wireguard.sync({ repoEngine: 'fixture-org/engine-cyberia', cmd: 'echo fleet' });
|
|
145
|
+
await Underpost.wireguard.sync({ repoEngine: 'fixture-org/engine-cyberia', dryRun: true });
|
|
146
|
+
|
|
147
|
+
expect(published).to.deep.equal([]);
|
|
148
|
+
});
|
|
149
|
+
});
|