@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,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host filesystem preparation for Kubernetes storage that unprivileged containers mount.
|
|
3
|
+
*
|
|
4
|
+
* Every node-local path a pod reaches through a `hostPath` PersistentVolume — or through a
|
|
5
|
+
* dynamic provisioner that is itself backed by a node directory — must carry a type the
|
|
6
|
+
* `container_t` domain can use. The base RHEL/Rocky policy has no mapping for the trees this
|
|
7
|
+
* platform writes into, so a directory created there falls back to the policy default
|
|
8
|
+
* (`default_t` under `/data`, `usr_t` under `/opt`, `user_home_t` under the operator's home) and
|
|
9
|
+
* every read and write from a pod becomes an AVC denial.
|
|
10
|
+
*
|
|
11
|
+
* The mapping is registered with `semanage fcontext` rather than applied with `chcon` so it
|
|
12
|
+
* survives a relabel, a policy update and `/.autorelabel`; the paths are then restored. Both
|
|
13
|
+
* operations are idempotent, which is what lets deploy, redeploy and recovery flows all call
|
|
14
|
+
* this without special-casing.
|
|
15
|
+
*
|
|
16
|
+
* @module src/server/security/container-storage.js
|
|
17
|
+
* @namespace ContainerStorageService
|
|
18
|
+
*/
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
import SELinuxService, { runSELinuxCommands, shellArgumentFactory } from './selinux.js';
|
|
22
|
+
import { HOST_VOLUME_ROOT } from '../runtime/environment.js';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Host storage preparation and SELinux labeling for container-mounted paths.
|
|
26
|
+
* @class ContainerStorageService
|
|
27
|
+
* @memberof ContainerStorageService
|
|
28
|
+
*/
|
|
29
|
+
class ContainerStorageService {
|
|
30
|
+
/** Label every unprivileged container domain can read and write, at the empty category set. */
|
|
31
|
+
static SHARED_CONTAINER_TYPE = SELinuxService.SHARED_CONTAINER_TYPE;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Mode used when this module is the one creating the directory. Existing directories keep the
|
|
35
|
+
* mode, ownership and ACLs they already have — the workload's own init container owns that,
|
|
36
|
+
* and resetting it would rewrite live data trees.
|
|
37
|
+
*/
|
|
38
|
+
static DEFAULT_MODE = '0755';
|
|
39
|
+
|
|
40
|
+
/** Upstream rancher local-path-provisioner defaults, used only when discovery finds nothing. */
|
|
41
|
+
static LOCAL_PATH_DEFAULT_ROOT = '/opt/local-path-provisioner';
|
|
42
|
+
static LOCAL_PATH_CONFIG_MAP = 'local-path-config';
|
|
43
|
+
static LOCAL_PATH_NAMESPACES = ['local-path-storage', 'kube-system'];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Node directories this platform owns and hands to containers. `/data` covers the MongoDB
|
|
47
|
+
* replica volumes, MariaDB, MySQL and PostgreSQL trees; `HOST_VOLUME_ROOT` covers every
|
|
48
|
+
* `hostPath` PersistentVolume the deploy flow materializes, including the gateway's static tree.
|
|
49
|
+
*/
|
|
50
|
+
static PLATFORM_STORAGE_ROOTS = ['/data', HOST_VOLUME_ROOT];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Kubernetes control-plane state bind-mounted into containers by kubeadm.
|
|
54
|
+
*/
|
|
55
|
+
static CONTROL_PLANE_MOUNT_PATHS = ['/etc/kubernetes', '/var/lib/etcd', '/var/lib/calico'];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Directories that are a system location in their own right. A storage tree may live *under*
|
|
59
|
+
* one of these (`/opt/local-path-provisioner`, `/var/lib/etcd`), but the directory itself never
|
|
60
|
+
* becomes container storage.
|
|
61
|
+
*/
|
|
62
|
+
static PROTECTED_EXACT_PATHS = [
|
|
63
|
+
'/',
|
|
64
|
+
'/boot',
|
|
65
|
+
'/dev',
|
|
66
|
+
'/etc',
|
|
67
|
+
'/home',
|
|
68
|
+
'/mnt',
|
|
69
|
+
'/opt',
|
|
70
|
+
'/proc',
|
|
71
|
+
'/root',
|
|
72
|
+
'/run',
|
|
73
|
+
'/srv',
|
|
74
|
+
'/sys',
|
|
75
|
+
'/tmp',
|
|
76
|
+
'/usr',
|
|
77
|
+
'/var',
|
|
78
|
+
'/var/lib',
|
|
79
|
+
'/var/log',
|
|
80
|
+
'/var/run',
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Trees no container storage may live in at all.
|
|
85
|
+
*
|
|
86
|
+
* A host directory being mounted into a pod is not evidence that it holds workload data: the
|
|
87
|
+
* CNI plugin directory, the runtime socket and `/proc` are all mounted into pods, and each has
|
|
88
|
+
* a policy type that exists for a reason. Relabeling `/opt/cni/bin` would strip `bin_t` from
|
|
89
|
+
* the calico executables the kubelet runs, which is a worse outcome than the denial it set out
|
|
90
|
+
* to fix.
|
|
91
|
+
*/
|
|
92
|
+
static PROTECTED_PATH_PREFIXES = [
|
|
93
|
+
'/bin',
|
|
94
|
+
'/boot',
|
|
95
|
+
'/dev',
|
|
96
|
+
'/etc',
|
|
97
|
+
'/lib',
|
|
98
|
+
'/lib64',
|
|
99
|
+
'/opt/cni',
|
|
100
|
+
'/proc',
|
|
101
|
+
'/run',
|
|
102
|
+
'/sbin',
|
|
103
|
+
'/sys',
|
|
104
|
+
'/usr',
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The one set of paths allowed to break {@link PROTECTED_PATH_PREFIXES}: kubeadm bind-mounts
|
|
109
|
+
* these into its control-plane containers, so they genuinely are container-visible state. They
|
|
110
|
+
* are a hardcoded constant, never something discovery or an operator flag can widen.
|
|
111
|
+
*/
|
|
112
|
+
static PROTECTED_PATH_EXCEPTIONS = ContainerStorageService.CONTROL_PLANE_MOUNT_PATHS;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Reports whether a path may be given the shared container label.
|
|
116
|
+
* @param {string} path - Absolute path.
|
|
117
|
+
* @returns {boolean}
|
|
118
|
+
*/
|
|
119
|
+
static isSafeStoragePath(path) {
|
|
120
|
+
if (typeof path !== 'string' || !path.startsWith('/')) return false;
|
|
121
|
+
const normalized = path.replace(/\/+$/, '') || '/';
|
|
122
|
+
if (ContainerStorageService.PROTECTED_PATH_EXCEPTIONS.includes(normalized)) return true;
|
|
123
|
+
if (ContainerStorageService.PROTECTED_EXACT_PATHS.includes(normalized)) return false;
|
|
124
|
+
return !ContainerStorageService.PROTECTED_PATH_PREFIXES.some(
|
|
125
|
+
(prefix) => normalized === prefix || normalized.startsWith(`${prefix}/`),
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Throws unless every path may be labeled. Applied at the command-building boundary so no
|
|
131
|
+
* caller — a discovery result, a CLI `extraPaths`, a future one — can route around it.
|
|
132
|
+
* @param {string[]} paths - Absolute paths.
|
|
133
|
+
* @returns {string[]} The same paths.
|
|
134
|
+
*/
|
|
135
|
+
static assertSafeStoragePaths(paths = []) {
|
|
136
|
+
const refused = paths.filter((path) => !ContainerStorageService.isSafeStoragePath(path));
|
|
137
|
+
if (refused.length > 0)
|
|
138
|
+
throw new RangeError(
|
|
139
|
+
`refusing to apply the container storage label to a system path: ${refused.join(', ')}. ` +
|
|
140
|
+
`A host directory mounted into a pod is not necessarily workload data; give the volume ` +
|
|
141
|
+
`its own directory under a declared storage root instead.`,
|
|
142
|
+
);
|
|
143
|
+
return paths;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Deduplicates and sorts a path list, keeping only absolute entries.
|
|
148
|
+
* @param {string[]} [paths] - Candidate paths.
|
|
149
|
+
* @returns {string[]} Absolute paths, parents before their descendants.
|
|
150
|
+
*/
|
|
151
|
+
static absoluteStoragePaths(paths = []) {
|
|
152
|
+
return [
|
|
153
|
+
...new Set(
|
|
154
|
+
paths
|
|
155
|
+
.filter((path) => typeof path === 'string')
|
|
156
|
+
.map((path) => path.trim().replace(/\/+$/, ''))
|
|
157
|
+
.filter((path) => path.startsWith('/') && path !== '/'),
|
|
158
|
+
),
|
|
159
|
+
].sort();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Reduces a path list to the smallest set of roots that still covers every entry.
|
|
164
|
+
*
|
|
165
|
+
* A `semanage fcontext` mapping is the regular expression `<root>(/.*)?`, so a root already
|
|
166
|
+
* covers all of its descendants; keeping both `/data` and `/data/mongodb` would add a redundant
|
|
167
|
+
* rule and a second full `restorecon` pass over the same tree on every deploy.
|
|
168
|
+
* @param {string[]} [paths] - Candidate absolute paths.
|
|
169
|
+
* @returns {string[]} Non-overlapping, sorted roots.
|
|
170
|
+
*/
|
|
171
|
+
static normalizeStorageRoots(paths = []) {
|
|
172
|
+
const absolute = ContainerStorageService.absoluteStoragePaths(paths);
|
|
173
|
+
return absolute.filter(
|
|
174
|
+
(path) => !absolute.some((candidate) => candidate !== path && path.startsWith(`${candidate}/`)),
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Extracts the node directories a local-path provisioner writes into, from its `config.json`.
|
|
180
|
+
*
|
|
181
|
+
* Read rather than assumed: the provisioner's root is operator-configurable, and every
|
|
182
|
+
* dynamically provisioned claim in this platform (Grafana, Prometheus, Alertmanager, IPFS,
|
|
183
|
+
* MariaDB) becomes a subdirectory of it. Labeling the wrong root leaves those claims with the
|
|
184
|
+
* `/opt` policy default (`usr_t`), which is exactly the shape of the Grafana denials.
|
|
185
|
+
* @param {string} [configJson] - Contents of the provisioner ConfigMap's `config.json` key.
|
|
186
|
+
* @returns {string[]} Configured node paths; empty when the config is absent or unparsable.
|
|
187
|
+
*/
|
|
188
|
+
static localPathRootsFactory(configJson = '') {
|
|
189
|
+
if (!configJson || !`${configJson}`.trim()) return [];
|
|
190
|
+
let config;
|
|
191
|
+
try {
|
|
192
|
+
config = JSON.parse(configJson);
|
|
193
|
+
} catch {
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
const paths = [];
|
|
197
|
+
if (Array.isArray(config?.nodePathMap))
|
|
198
|
+
for (const entry of config.nodePathMap) if (Array.isArray(entry?.paths)) paths.push(...entry.paths);
|
|
199
|
+
if (typeof config?.sharedFileSystemPath === 'string') paths.push(config.sharedFileSystemPath);
|
|
200
|
+
return ContainerStorageService.normalizeStorageRoots(paths);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Builds the command that creates a storage directory only when it is missing.
|
|
205
|
+
*
|
|
206
|
+
* Guarded rather than unconditional: `install -d -m` on an existing tree would rewrite the
|
|
207
|
+
* mode a workload's init container set (MongoDB's `chown 999:999`, MariaDB's data dir), and
|
|
208
|
+
* this runs on every redeploy.
|
|
209
|
+
* @param {string} path - Absolute directory path.
|
|
210
|
+
* @param {{mode?: string, owner?: string, sudo?: boolean}} [options]
|
|
211
|
+
* @returns {string} Shell command.
|
|
212
|
+
*/
|
|
213
|
+
static storageDirectoryCommandFactory(
|
|
214
|
+
path,
|
|
215
|
+
{ mode = ContainerStorageService.DEFAULT_MODE, owner = '', sudo = true } = {},
|
|
216
|
+
) {
|
|
217
|
+
if (!path) throw new TypeError('storageDirectoryCommandFactory requires a path');
|
|
218
|
+
const prefix = sudo ? 'sudo ' : '';
|
|
219
|
+
const quoted = shellArgumentFactory(path);
|
|
220
|
+
const ownerFlag = owner
|
|
221
|
+
? ` -o ${shellArgumentFactory(`${owner}`.split(':')[0])}${
|
|
222
|
+
`${owner}`.includes(':') ? ` -g ${shellArgumentFactory(`${owner}`.split(':')[1])}` : ''
|
|
223
|
+
}`
|
|
224
|
+
: '';
|
|
225
|
+
return `[ -d ${quoted} ] || ${prefix}install -d -m ${mode}${ownerFlag} ${quoted}`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Builds the full idempotent preparation for one or more container-mounted storage roots:
|
|
230
|
+
* create when missing, register the persistent `container_file_t` mapping, restore the tree.
|
|
231
|
+
* @param {string|string[]} paths - Absolute directories.
|
|
232
|
+
* @param {{mode?: string, owner?: string, sudo?: boolean}} [options]
|
|
233
|
+
* @returns {string[]} Commands, in execution order.
|
|
234
|
+
*/
|
|
235
|
+
static containerStorageCommandsFactory(paths, options = {}) {
|
|
236
|
+
const requested = ContainerStorageService.absoluteStoragePaths(Array.isArray(paths) ? paths : [paths]);
|
|
237
|
+
if (requested.length === 0)
|
|
238
|
+
throw new TypeError('containerStorageCommandsFactory requires at least one absolute path');
|
|
239
|
+
ContainerStorageService.assertSafeStoragePaths(requested);
|
|
240
|
+
// Every requested path is created — a nested one (`/data/mysql`) is a real directory a PV
|
|
241
|
+
// mounts. Mapping and restoring collapse to the covering roots: an fcontext expression is
|
|
242
|
+
// `<root>(/.*)?`, so a nested entry would add a redundant rule to the local policy store and
|
|
243
|
+
// a second full relabel pass over the same tree on every deploy.
|
|
244
|
+
return [
|
|
245
|
+
...requested.map((path) => ContainerStorageService.storageDirectoryCommandFactory(path, options)),
|
|
246
|
+
...ContainerStorageService.containerStorageSubtreeCommandsFactory(requested, {
|
|
247
|
+
sudo: options.sudo !== false,
|
|
248
|
+
}),
|
|
249
|
+
];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Resolves which declared storage root covers a path.
|
|
254
|
+
* @param {string} path - Absolute path.
|
|
255
|
+
* @param {string[]} [roots] - Candidate roots.
|
|
256
|
+
* @returns {string} The covering root, or the path itself when none covers it.
|
|
257
|
+
*/
|
|
258
|
+
static coveringRootFactory(path, roots = ContainerStorageService.PLATFORM_STORAGE_ROOTS) {
|
|
259
|
+
const covering = ContainerStorageService.absoluteStoragePaths(roots)
|
|
260
|
+
.filter((root) => path === root || path.startsWith(`${root}/`))
|
|
261
|
+
.sort((a, b) => b.length - a.length)[0];
|
|
262
|
+
return covering || path;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Builds the preparation for one subtree of an already-declared storage root: the persistent
|
|
267
|
+
* mapping is registered on the covering root, and only the subtree is restored.
|
|
268
|
+
*
|
|
269
|
+
* A per-volume mapping would grow the local policy store by one `semanage fcontext` rule for
|
|
270
|
+
* every PersistentVolume the deploy flow has ever materialized, and every one of those rules is
|
|
271
|
+
* then evaluated on each relabel. One rule on the root already covers all of them, and it is
|
|
272
|
+
* what makes a volume created later — by kubelet's `DirectoryOrCreate`, or by the local-path
|
|
273
|
+
* helper pod — inherit the right label without another pass.
|
|
274
|
+
* @param {string|string[]} paths - Absolute subtrees to restore.
|
|
275
|
+
* @param {{roots?: string[], mode?: string, owner?: string, sudo?: boolean}} [options]
|
|
276
|
+
* @returns {string[]} Commands, in execution order.
|
|
277
|
+
*/
|
|
278
|
+
static containerStorageSubtreeCommandsFactory(paths, { roots, ...options } = {}) {
|
|
279
|
+
const subtrees = ContainerStorageService.absoluteStoragePaths(Array.isArray(paths) ? paths : [paths]);
|
|
280
|
+
if (subtrees.length === 0)
|
|
281
|
+
throw new TypeError('containerStorageSubtreeCommandsFactory requires at least one absolute path');
|
|
282
|
+
const sudo = options.sudo !== false;
|
|
283
|
+
ContainerStorageService.assertSafeStoragePaths(subtrees);
|
|
284
|
+
const mapped = ContainerStorageService.normalizeStorageRoots(
|
|
285
|
+
subtrees.map((path) => ContainerStorageService.coveringRootFactory(path, roots)),
|
|
286
|
+
);
|
|
287
|
+
// The mapped root is what the fcontext rule covers, so it is checked too: a subtree that is
|
|
288
|
+
// itself safe must never resolve up into a root that is not.
|
|
289
|
+
ContainerStorageService.assertSafeStoragePaths(mapped);
|
|
290
|
+
return [
|
|
291
|
+
...mapped.map((root) =>
|
|
292
|
+
SELinuxService.selinuxFileContextCommandFactory(root, {
|
|
293
|
+
type: ContainerStorageService.SHARED_CONTAINER_TYPE,
|
|
294
|
+
sudo,
|
|
295
|
+
}),
|
|
296
|
+
),
|
|
297
|
+
SELinuxService.selinuxRestoreconCommandFactory(ContainerStorageService.normalizeStorageRoots(subtrees), {
|
|
298
|
+
sudo,
|
|
299
|
+
}),
|
|
300
|
+
];
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Executes {@link containerStorageSubtreeCommandsFactory}.
|
|
305
|
+
* @param {string|string[]} paths - Absolute subtrees.
|
|
306
|
+
* @param {{execute: Function, roots?: string[], sudo?: boolean}} options
|
|
307
|
+
* @returns {*[]} Executor results.
|
|
308
|
+
*/
|
|
309
|
+
static ensureContainerStorageSubtree(paths, { execute, ...options } = {}) {
|
|
310
|
+
return runSELinuxCommands(ContainerStorageService.containerStorageSubtreeCommandsFactory(paths, options), {
|
|
311
|
+
execute,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Executes {@link containerStorageCommandsFactory}.
|
|
317
|
+
* @param {string|string[]} paths - Absolute directories.
|
|
318
|
+
* @param {{execute: Function, mode?: string, owner?: string, sudo?: boolean}} options
|
|
319
|
+
* @returns {*[]} Executor results.
|
|
320
|
+
*/
|
|
321
|
+
static ensureContainerStorage(paths, { execute, ...options } = {}) {
|
|
322
|
+
return runSELinuxCommands(ContainerStorageService.containerStorageCommandsFactory(paths, options), { execute });
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Command that prints the local-path provisioner `config.json`, or nothing when absent.
|
|
327
|
+
* @param {{namespace: string, configMap?: string}} options
|
|
328
|
+
* @returns {string} Shell command.
|
|
329
|
+
*/
|
|
330
|
+
static localPathConfigCommandFactory({ namespace, configMap = ContainerStorageService.LOCAL_PATH_CONFIG_MAP } = {}) {
|
|
331
|
+
if (!namespace) throw new TypeError('localPathConfigCommandFactory requires a namespace');
|
|
332
|
+
return `kubectl get configmap ${configMap} -n ${namespace} -o jsonpath='{.data.config\\.json}' 2>/dev/null || true`;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Resolves every node directory that must carry the shared container label on this host.
|
|
337
|
+
* @param {{localPathRoots?: string[], extraPaths?: string[], controlPlane?: boolean}} [options]
|
|
338
|
+
* @returns {string[]} Non-overlapping roots.
|
|
339
|
+
*/
|
|
340
|
+
static containerStorageRootsFactory({ localPathRoots = [], extraPaths = [], controlPlane = false } = {}) {
|
|
341
|
+
return ContainerStorageService.normalizeStorageRoots([
|
|
342
|
+
...ContainerStorageService.PLATFORM_STORAGE_ROOTS,
|
|
343
|
+
...(controlPlane ? ContainerStorageService.CONTROL_PLANE_MOUNT_PATHS : []),
|
|
344
|
+
...(localPathRoots.length > 0 ? localPathRoots : [ContainerStorageService.LOCAL_PATH_DEFAULT_ROOT]),
|
|
345
|
+
...extraPaths,
|
|
346
|
+
]);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const {
|
|
351
|
+
absoluteStoragePaths,
|
|
352
|
+
isSafeStoragePath,
|
|
353
|
+
assertSafeStoragePaths,
|
|
354
|
+
containerStorageCommandsFactory,
|
|
355
|
+
containerStorageRootsFactory,
|
|
356
|
+
containerStorageSubtreeCommandsFactory,
|
|
357
|
+
coveringRootFactory,
|
|
358
|
+
ensureContainerStorage,
|
|
359
|
+
ensureContainerStorageSubtree,
|
|
360
|
+
localPathConfigCommandFactory,
|
|
361
|
+
localPathRootsFactory,
|
|
362
|
+
normalizeStorageRoots,
|
|
363
|
+
storageDirectoryCommandFactory,
|
|
364
|
+
} = ContainerStorageService;
|
|
365
|
+
|
|
366
|
+
export default ContainerStorageService;
|
|
367
|
+
|
|
368
|
+
export {
|
|
369
|
+
absoluteStoragePaths,
|
|
370
|
+
isSafeStoragePath,
|
|
371
|
+
assertSafeStoragePaths,
|
|
372
|
+
containerStorageCommandsFactory,
|
|
373
|
+
containerStorageRootsFactory,
|
|
374
|
+
containerStorageSubtreeCommandsFactory,
|
|
375
|
+
coveringRootFactory,
|
|
376
|
+
ensureContainerStorage,
|
|
377
|
+
ensureContainerStorageSubtree,
|
|
378
|
+
localPathConfigCommandFactory,
|
|
379
|
+
localPathRootsFactory,
|
|
380
|
+
normalizeStorageRoots,
|
|
381
|
+
storageDirectoryCommandFactory,
|
|
382
|
+
};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Manages backup operations for deployments.
|
|
3
|
-
* @module src/server/backup.js
|
|
3
|
+
* @module src/server/storage/backup.js
|
|
4
4
|
* @namespace UnderpostBakcUp
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import fs from 'fs-extra';
|
|
8
|
-
import { loggerFactory } from '
|
|
9
|
-
import Underpost from '
|
|
10
|
-
import { loadCronDeployEnv } from '
|
|
8
|
+
import { loggerFactory } from '../ops/logger.js';
|
|
9
|
+
import Underpost from '../../index.js';
|
|
10
|
+
import { loadCronDeployEnv } from '../ops/cron.js';
|
|
11
|
+
import { readDeployRoutes } from '../network/router.js';
|
|
11
12
|
|
|
12
13
|
const logger = loggerFactory(import.meta);
|
|
13
14
|
|
|
@@ -39,13 +40,13 @@ class BackUp {
|
|
|
39
40
|
static callback = async function (deployList, options = { git: false }) {
|
|
40
41
|
const firstDeployId = deployList && deployList !== 'dd' ? deployList.split(',')[0].trim() : '';
|
|
41
42
|
loadCronDeployEnv();
|
|
42
|
-
if (
|
|
43
|
-
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').trim();
|
|
43
|
+
if (!deployList || deployList === 'dd') deployList = readDeployRoutes().join(',');
|
|
44
44
|
|
|
45
45
|
logger.info('init backups callback', deployList);
|
|
46
46
|
await logger.setUpInfo();
|
|
47
47
|
|
|
48
48
|
const clusterFlag = options.k3s ? ' --k3s' : options.kind ? ' --kind' : options.kubeadm ? ' --kubeadm' : '';
|
|
49
|
+
const failures = [];
|
|
49
50
|
|
|
50
51
|
for (const _deployId of deployList.split(',')) {
|
|
51
52
|
const deployId = _deployId.trim();
|
|
@@ -71,7 +72,8 @@ class BackUp {
|
|
|
71
72
|
cd: '/home/dd/engine',
|
|
72
73
|
});
|
|
73
74
|
} catch (err) {
|
|
74
|
-
|
|
75
|
+
failures.push({ deployId, phase: 'database-export', error: err.message });
|
|
76
|
+
logger.error(`Error during database export for ${deployId}`, { error: err.message });
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
// Repository backup: Cron container → SSH to host → host finds pod → kubectl exec git backup
|
|
@@ -83,9 +85,16 @@ class BackUp {
|
|
|
83
85
|
cd: '/home/dd/engine',
|
|
84
86
|
});
|
|
85
87
|
} catch (err) {
|
|
86
|
-
|
|
88
|
+
failures.push({ deployId, phase: 'repository-backup', error: err.message });
|
|
89
|
+
logger.error(`Error during repository backup for ${deployId}`, { error: err.message });
|
|
87
90
|
}
|
|
88
91
|
}
|
|
92
|
+
|
|
93
|
+
// One deploy-id failing must not abort the remaining ones, so the loop swallows
|
|
94
|
+
// per-phase errors — this summary is the only place the run's real outcome shows up.
|
|
95
|
+
// The failing `shellExec` has already latched `container-status=error` for monitoring.
|
|
96
|
+
if (failures.length > 0) logger.error('Backup completed with failures', { count: failures.length, failures });
|
|
97
|
+
else logger.info('Backup completed for all deploy-ids', { deployList });
|
|
89
98
|
};
|
|
90
99
|
}
|
|
91
100
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Module for parsing data query parameters into Mongoose query options.
|
|
3
3
|
* Supports AG Grid filterModel/sortModel as well as simple legacy parameters.
|
|
4
|
-
* @module src/server/data-query.js
|
|
4
|
+
* @module src/server/storage/data-query.js
|
|
5
5
|
* @namespace DataQuery
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -15,6 +15,22 @@
|
|
|
15
15
|
* @memberof DataQuery
|
|
16
16
|
*/
|
|
17
17
|
class DataQuery {
|
|
18
|
+
/**
|
|
19
|
+
* Filter that addresses one document by its natural key.
|
|
20
|
+
*
|
|
21
|
+
* The natural key is the value people navigate by: an object layer item id, an
|
|
22
|
+
* instance code. A key shaped like a document id matches either field, so a
|
|
23
|
+
* document id still resolves.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} field - Path of the natural key, e.g. 'data.item.id'.
|
|
26
|
+
* @param {string} key - The key taken from the request.
|
|
27
|
+
* @memberof DataQuery
|
|
28
|
+
* @returns {Object} A Mongoose filter selecting at most one document.
|
|
29
|
+
*/
|
|
30
|
+
static naturalKeyFilter(field, key) {
|
|
31
|
+
return /^[0-9a-f]{24}$/i.test(String(key)) ? { $or: [{ [field]: key }, { _id: key }] } : { [field]: key };
|
|
32
|
+
}
|
|
33
|
+
|
|
18
34
|
/**
|
|
19
35
|
* Parse request query parameters into Mongoose query options
|
|
20
36
|
* @param {Object} params - The request query parameters (req.query)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides a utility class for downloading files from a URL and saving them to the local filesystem.
|
|
3
|
+
* @module src/server/storage/downloader.js
|
|
4
|
+
* @namespace Downloader
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import axios from 'axios';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import { loggerFactory } from '../ops/logger.js';
|
|
10
|
+
|
|
11
|
+
const logger = loggerFactory(import.meta);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Main class for handling file downloading operations.
|
|
15
|
+
* All utility methods are implemented as static to serve as a namespace container.
|
|
16
|
+
* @class Downloader
|
|
17
|
+
* @augments Downloader
|
|
18
|
+
* @memberof Downloader
|
|
19
|
+
*/
|
|
20
|
+
class Downloader {
|
|
21
|
+
/**
|
|
22
|
+
* Downloads a file from a given URL and pipes the stream to a local file path.
|
|
23
|
+
* @static
|
|
24
|
+
* @memberof Downloader
|
|
25
|
+
* @param {string} url The URL of the file to download.
|
|
26
|
+
* @param {string} fullPath The full local path where the file should be saved.
|
|
27
|
+
* @param {object} [options] Axios request configuration options.
|
|
28
|
+
* @param {string} [options.method='get'] HTTP method.
|
|
29
|
+
* @param {string} [options.responseType='stream'] Expected response type.
|
|
30
|
+
* @returns {Promise<string>} Resolves with the full path of the saved file on success.
|
|
31
|
+
* @memberof Downloader
|
|
32
|
+
*/
|
|
33
|
+
static downloadFile(url, fullPath, options = { method: 'get', responseType: 'stream' }) {
|
|
34
|
+
/**
|
|
35
|
+
* Renders an error response body, whatever transport shape it arrived in, capped for a log
|
|
36
|
+
* line. A stream request carries even its errors as a stream, so the body has to be read
|
|
37
|
+
* before it can be reported.
|
|
38
|
+
*/
|
|
39
|
+
const responseBody = async (data) => {
|
|
40
|
+
if (!data) return undefined;
|
|
41
|
+
try {
|
|
42
|
+
if (Buffer.isBuffer(data)) return data.toString('utf8').slice(0, 500);
|
|
43
|
+
if (typeof data === 'string') return data.slice(0, 500);
|
|
44
|
+
if (typeof data.on === 'function') {
|
|
45
|
+
let text = '';
|
|
46
|
+
for await (const chunk of data) {
|
|
47
|
+
text += chunk;
|
|
48
|
+
if (text.length > 500) break;
|
|
49
|
+
}
|
|
50
|
+
return text.slice(0, 500) || undefined;
|
|
51
|
+
}
|
|
52
|
+
return JSON.stringify(data).slice(0, 500);
|
|
53
|
+
} catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return new Promise((resolve, reject) => {
|
|
59
|
+
let settled = false;
|
|
60
|
+
const fail = (error) => {
|
|
61
|
+
if (settled) return;
|
|
62
|
+
settled = true;
|
|
63
|
+
logger.error('Error downloading the file', { fullPath, error: error?.message });
|
|
64
|
+
// A partial file is worse than none: the caller cannot tell it apart from a whole one.
|
|
65
|
+
if (fs.existsSync(fullPath)) fs.unlinkSync(fullPath);
|
|
66
|
+
return reject(error);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
axios({
|
|
70
|
+
url,
|
|
71
|
+
...options,
|
|
72
|
+
})
|
|
73
|
+
.then((response) => {
|
|
74
|
+
const writer = fs.createWriteStream(fullPath);
|
|
75
|
+
const expectedBytes = Number(response.headers?.['content-length'] ?? NaN);
|
|
76
|
+
|
|
77
|
+
// A response stream that ends early still ends, so the writer emits `finish` and the
|
|
78
|
+
// download reports success over a truncated file. The declared length is what proves
|
|
79
|
+
// the transfer whole — without this check a short part reached the caller intact-looking
|
|
80
|
+
// and only surfaced much later, as a corrupt archive assembled from it.
|
|
81
|
+
writer.on('finish', () => {
|
|
82
|
+
if (settled) return;
|
|
83
|
+
const receivedBytes = writer.bytesWritten;
|
|
84
|
+
if (Number.isFinite(expectedBytes) && receivedBytes !== expectedBytes)
|
|
85
|
+
return fail(new Error(`Truncated download: expected ${expectedBytes} bytes, received ${receivedBytes}`));
|
|
86
|
+
settled = true;
|
|
87
|
+
logger.info('Download complete', { fullPath, bytes: receivedBytes });
|
|
88
|
+
return resolve(fullPath);
|
|
89
|
+
});
|
|
90
|
+
writer.on('error', fail);
|
|
91
|
+
response.data.on('error', fail);
|
|
92
|
+
response.data.pipe(writer);
|
|
93
|
+
})
|
|
94
|
+
.catch(async (error) => {
|
|
95
|
+
// The status alone names nothing. A storage service explains a refusal in the body —
|
|
96
|
+
// which delivery type it looked under, which id it could not find — and without it a
|
|
97
|
+
// caller sees `status code 400` and has to reproduce the request by hand to learn why.
|
|
98
|
+
logger.error('Error in the request', {
|
|
99
|
+
fullPath,
|
|
100
|
+
error: error?.message,
|
|
101
|
+
status: error?.response?.status,
|
|
102
|
+
body: await responseBody(error?.response?.data),
|
|
103
|
+
});
|
|
104
|
+
return reject(error);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default Downloader;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @function downloadFile
|
|
114
|
+
* @description Backward compatibility export for `Downloader.downloadFile`.
|
|
115
|
+
* @param {string} url The URL of the file to download.
|
|
116
|
+
* @param {string} fullPath The full local path where the file should be saved.
|
|
117
|
+
* @param {object} [options] Axios request configuration options.
|
|
118
|
+
* @returns {Promise<string>} Resolves with the full path of the saved file on success.
|
|
119
|
+
* @memberof Downloader
|
|
120
|
+
*/
|
|
121
|
+
export const downloadFile = Downloader.downloadFile;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository identity: who owns the source this build came from, and the
|
|
3
|
+
* canonical URLs derived from it.
|
|
4
|
+
*
|
|
5
|
+
* Every environment publishes from a different fork, so an owner baked into a
|
|
6
|
+
* component renders a link to someone else's repository. The owner is resolved
|
|
7
|
+
* once here, travels to the client in `renderPayload.repository`, and is the
|
|
8
|
+
* only thing any GitHub, Pages or Coveralls URL is composed from.
|
|
9
|
+
*
|
|
10
|
+
* @module src/server/storage/repository.js
|
|
11
|
+
* @namespace ServerRepository
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { environmentValueFactory } from '../runtime/environment.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @constant REPOSITORY_DEFAULTS
|
|
18
|
+
* @description Fallbacks for a tree published without repository environment.
|
|
19
|
+
* The only place in the codebase allowed to name an owner or a repository.
|
|
20
|
+
* @memberof ServerRepository
|
|
21
|
+
*/
|
|
22
|
+
const REPOSITORY_DEFAULTS = {
|
|
23
|
+
owner: 'underpostnet',
|
|
24
|
+
name: 'engine',
|
|
25
|
+
template: 'pwa-microservices-template',
|
|
26
|
+
// Prebuilt package repositories are the template repository plus this suffix.
|
|
27
|
+
packageSuffix: '-ghpkg',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @method repositoryIdentityFactory
|
|
32
|
+
* @description Resolves the repository identity this build publishes under.
|
|
33
|
+
* @param {object} [overrides] - Explicit values that win over the environment.
|
|
34
|
+
* @returns {{owner: string, name: string, template: string, packageSuffix: string}} Identity.
|
|
35
|
+
* @memberof ServerRepository
|
|
36
|
+
*/
|
|
37
|
+
const repositoryIdentityFactory = (overrides = {}) => ({
|
|
38
|
+
...REPOSITORY_DEFAULTS,
|
|
39
|
+
...(environmentValueFactory('GITHUB_USERNAME') ? { owner: environmentValueFactory('GITHUB_USERNAME') } : {}),
|
|
40
|
+
...Object.fromEntries(Object.entries(overrides).filter(([, value]) => value)),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @method githubUrlFactory
|
|
45
|
+
* @description Composes a github.com URL under the resolved owner.
|
|
46
|
+
* @param {object} [params]
|
|
47
|
+
* @param {object} [params.identity] - Identity to compose against.
|
|
48
|
+
* @param {string[]} [params.segments] - Path segments after the owner.
|
|
49
|
+
* @returns {string} Absolute URL, trailing slash included.
|
|
50
|
+
* @memberof ServerRepository
|
|
51
|
+
*/
|
|
52
|
+
const githubUrlFactory = ({ identity = repositoryIdentityFactory(), segments = [] } = {}) =>
|
|
53
|
+
`https://github.com/${[identity.owner, ...segments].filter(Boolean).join('/')}/`;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @method githubCommitUrlFactory
|
|
57
|
+
* @description Markdown link to one commit, for generated changelogs.
|
|
58
|
+
* @param {object} params
|
|
59
|
+
* @param {string} params.shortHash - Abbreviated hash used as the link text.
|
|
60
|
+
* @param {string} params.hash - Full hash the link resolves to.
|
|
61
|
+
* @param {object} [params.identity] - Identity to compose against.
|
|
62
|
+
* @returns {string} Markdown link.
|
|
63
|
+
* @memberof ServerRepository
|
|
64
|
+
*/
|
|
65
|
+
const githubCommitUrlFactory = ({ shortHash, hash, identity = repositoryIdentityFactory() }) =>
|
|
66
|
+
`[${shortHash}](https://github.com/${identity.owner}/${identity.name}/commit/${hash})`;
|
|
67
|
+
|
|
68
|
+
export { REPOSITORY_DEFAULTS, githubCommitUrlFactory, githubUrlFactory, repositoryIdentityFactory };
|