@underpostnet/cyberia 3.3.73 → 3.3.77
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/.env.example +17 -5
- package/.github/workflows/coverall.cyberia.ci.yml +10 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-server.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +1 -1
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +1 -1
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +1 -1
- package/.github/workflows/engine-cyberia.ci.yml +1 -1
- package/.github/workflows/publish.cyberia.ci.yml +44 -0
- package/AGENTS.md +61 -12
- package/CHANGELOG.md +159 -161
- package/CLI-HELP.md +20 -13
- package/Dockerfile +1 -1
- package/Dockerfile.dev +1 -1
- package/Dockerfile.test +2 -2
- package/README.md +28 -28
- package/bin/build.js +96 -21
- package/bin/cyberia.js +1247 -1373
- package/bin/index.js +1247 -1373
- package/compose.env +17 -5
- package/conf.js +7 -4
- package/deploy/cyberia-client/deploy.sh +10 -11
- package/deploy/cyberia-client/package.sh +0 -1
- package/deploy/cyberia-client/state.sh +3 -2
- package/deploy/cyberia-server/deploy.sh +10 -11
- package/deploy/cyberia-server/package.sh +0 -1
- package/deploy/cyberia-server/state.sh +3 -2
- package/deploy/dd-cyberia/deploy.sh +5 -5
- package/deploy/dd-cyberia/init.sh +15 -14
- package/deploy/dd-cyberia/package.sh +0 -1
- package/deploy/dd-cyberia/state.sh +2 -2
- package/deploy/dd-cyberia/sync-deploy.sh +139 -75
- package/deploy/lib/config.sh +29 -0
- package/deploy/lib/github-actions-logging.sh +92 -76
- package/deploy/lib/host.sh +28 -19
- package/deploy/lib/state.sh +4 -1
- package/deploy/pwa-microservices-template/deploy.sh +10 -8
- package/deploy/release/deploy.sh +0 -2
- package/deployment.yaml +1 -1
- package/docker-compose.yml +23 -17
- package/docs/coverage/cyberia/api/cyberia-instance/cyberia-fallback-capture.js.html +1591 -0
- package/docs/coverage/cyberia/api/cyberia-instance/index.html +116 -0
- package/docs/coverage/cyberia/api/cyberia-server-defaults/cyberia-server-defaults.js.html +4138 -0
- package/docs/coverage/cyberia/api/cyberia-server-defaults/index.html +116 -0
- package/docs/coverage/cyberia/api/object-layer/index.html +116 -0
- package/docs/coverage/cyberia/api/object-layer/object-layer.model.js.html +1393 -0
- package/docs/coverage/cyberia/base.css +362 -0
- package/docs/coverage/cyberia/block-navigation.js +82 -0
- package/docs/coverage/cyberia/favicon.png +0 -0
- package/docs/coverage/cyberia/index.html +161 -0
- package/docs/coverage/cyberia/prettify.css +101 -0
- package/docs/coverage/cyberia/prettify.js +937 -0
- package/docs/coverage/cyberia/projects/cyberia/atlas-sprite-sheet-generator.js.html +1315 -0
- package/docs/coverage/cyberia/projects/cyberia/index.html +176 -0
- package/docs/coverage/cyberia/projects/cyberia/instance-backup.js.html +715 -0
- package/docs/coverage/cyberia/projects/cyberia/instance-data.js.html +2182 -0
- package/docs/coverage/cyberia/projects/cyberia/shape-generator.js.html +3265 -0
- package/docs/coverage/cyberia/projects/cyberia/stat-balance.js.html +328 -0
- package/docs/coverage/cyberia/sort-arrow-sprite.png +0 -0
- package/docs/coverage/cyberia/sorter.js +205 -0
- package/hardhat/package-lock.json +2 -2
- package/hardhat/package.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +1 -1
- 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/package.json +19 -17
- package/scripts/test-monitor.sh +3 -3
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +14 -9
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +88 -184
- package/src/api/cyberia-action/cyberia-action.router.js +2 -2
- package/src/api/cyberia-action/cyberia-action.service.js +3 -4
- 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 +1 -3
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +12 -34
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +15 -32
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +1 -1
- 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 +16 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +466 -3
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +87 -51
- package/src/api/cyberia-instance/cyberia-fallback-world.js +21 -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 +34 -141
- package/src/api/cyberia-instance/cyberia-instance.controller.js +1 -4
- package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
- package/src/api/cyberia-instance/cyberia-instance.router.js +3 -16
- package/src/api/cyberia-instance/cyberia-instance.service.js +3 -43
- package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +74 -1
- package/src/api/cyberia-map/cyberia-map.service.js +6 -2
- 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.router.js +3 -3
- package/src/api/cyberia-quest/cyberia-quest.service.js +3 -3
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -188
- package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
- package/src/api/file/file.ref.js +153 -0
- package/src/api/file/file.ref.json +11 -2
- package/src/api/object-layer/object-layer.model.js +47 -12
- package/src/api/object-layer/object-layer.router.js +10 -3
- package/src/api/object-layer/object-layer.service.js +113 -120
- package/src/cli/app.js +12 -1
- package/src/cli/client.js +2 -2
- package/src/cli/cluster.js +80 -18
- package/src/cli/deploy.js +215 -34
- package/src/cli/docker-compose.js +1 -1
- package/src/cli/fs-selection.js +115 -0
- package/src/cli/fs.js +158 -342
- package/src/cli/index.js +22 -10
- package/src/cli/release.js +3 -1
- package/src/cli/repository.js +35 -9
- package/src/cli/run.js +80 -199
- package/src/cli/test.js +4 -0
- package/src/cli/wireguard.js +32 -31
- package/src/client/components/core/Badge.js +0 -1
- package/src/client/components/core/CssCore.js +8 -1
- package/src/client/components/core/Docs.js +77 -100
- package/src/client/components/core/Modal.js +77 -23
- package/src/client/components/core/ToolTip.js +15 -0
- package/src/client/components/cryptokoyn/AppShellCryptokoyn.js +0 -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 +0 -34
- 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/RouterCyberiaPortal.js +0 -4
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
- package/src/client/components/default/AppShellDefault.js +1 -4
- package/src/client/components/itemledger/AppShellItemledger.js +0 -2
- package/src/client/components/underpost/AppShellUnderpost.js +1 -1
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +280 -24
- 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 +28 -28
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
- 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/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/views/Cyberia404.js +3 -3
- package/src/client-builder/client-build-docs.js +52 -52
- package/src/client-builder/client-build.js +67 -44
- package/src/client-builder/client-bundle.js +347 -0
- package/src/db/mongo/MongoExpress.js +187 -0
- package/src/grpc/cyberia/grpc-server.js +5 -7
- package/src/index.js +1 -1
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +143 -146
- package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
- package/src/projects/cyberia/besu-genesis-generator.js +5 -14
- package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
- package/src/projects/cyberia/catalog-cyberia.js +3 -2
- package/src/projects/cyberia/gemini-client.js +3 -3
- package/src/projects/cyberia/generate-saga.js +4 -11
- package/src/projects/cyberia/hot-reload-trigger.js +17 -28
- package/src/projects/cyberia/instance-backup.js +210 -0
- package/src/projects/cyberia/instance-data.js +177 -257
- package/src/projects/cyberia/map-preview-generator.js +32 -68
- package/src/projects/cyberia/object-layer.js +152 -319
- 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 +2 -18
- 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/runtime/cyberia-client/Dockerfile +8 -4
- package/src/runtime/cyberia-client/Dockerfile.dev +5 -2
- package/src/runtime/cyberia-server/Dockerfile +9 -2
- package/src/runtime/cyberia-server/Dockerfile.dev +8 -1
- package/src/runtime/engine-cyberia/Dockerfile +1 -1
- package/src/runtime/engine-cyberia/Dockerfile.dev +1 -1
- package/src/runtime/engine-cyberia/Dockerfile.test +2 -2
- package/src/runtime/engine-cyberia/compose.env +17 -5
- package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
- package/src/server/build/coverage.js +113 -42
- package/src/server/build/package.js +55 -12
- package/src/server/build/testing.js +59 -9
- package/src/server/network/middlewares.js +8 -2
- package/src/server/network/underpost-gateway.js +113 -14
- package/src/server/ops/logger.js +70 -35
- package/src/server/runtime/conf.js +40 -9
- package/src/server/runtime/start.js +11 -2
- package/src/server/storage/data-query.js +16 -0
- package/src/server/storage/downloader.js +62 -14
- package/src/server/storage/zip.js +153 -0
- 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 +34 -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/integration/app/cyberia/cyberia-instance-conf-defaults.test.js +16 -22
- package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
- package/test/integration/app/cyberia/cyberia-load.test.js +6 -7
- 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 +87 -2
- 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/integration/infra/2-network/wireguard-cli.test.js +33 -9
- package/test/integration/infra/2-network/wireguard-edge.test.js +58 -18
- 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/underpost-ingress.test.js +1 -1
- package/test/unit/catalog.test.js +13 -2
- package/test/unit/client-build-docs.test.js +97 -70
- package/test/unit/client-bundle.test.js +313 -0
- package/test/unit/conf-resolution.test.js +58 -7
- package/test/unit/coverage-artifact.test.js +120 -29
- package/test/unit/cyberia/instance-backup.test.js +183 -0
- package/test/unit/cyberia/instance-data.test.js +314 -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-legacy-gateway-sweep.test.js +63 -0
- package/test/unit/deploy-log-table.test.js +76 -5
- package/test/unit/downloader-integrity.test.js +98 -0
- package/test/unit/file-reference-registry.test.js +141 -0
- package/test/unit/fs-storage-paths.test.js +596 -0
- package/test/unit/gateway-pod-fetch.test.js +95 -0
- package/test/unit/letsencrypt-issuer.test.js +101 -0
- package/test/unit/logger-redaction.test.js +29 -0
- package/test/unit/package.test.js +70 -16
- package/test/unit/prepare-host.test.js +84 -1
- package/test/unit/release-bump.test.js +3 -1
- package/test/unit/start-options.test.js +12 -0
- package/test/unit/test-tiers.test.js +27 -0
- package/test/unit/zip-archive.test.js +142 -0
- package/vitest.config.js +11 -3
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
|
@@ -1413,9 +1413,9 @@ describe('engine sync', () => {
|
|
|
1413
1413
|
const commands = UnderpostWireguard.API.syncCommands().map((step) => step.command);
|
|
1414
1414
|
expect(commands.join('\n')).to.not.match(/<[a-z-]+>/);
|
|
1415
1415
|
expect(commands.some((command) => command.includes('package.sh'))).to.equal(false);
|
|
1416
|
-
expect(commands).to.include('
|
|
1416
|
+
expect(commands).to.include('node bin cmt --switch-repo someone/engine --target-branch master');
|
|
1417
1417
|
expect(commands).to.include(
|
|
1418
|
-
'
|
|
1418
|
+
'node bin cmt ./engine-private --switch-repo someone/engine-private --target-branch main',
|
|
1419
1419
|
);
|
|
1420
1420
|
});
|
|
1421
1421
|
|
|
@@ -1424,9 +1424,9 @@ describe('engine sync', () => {
|
|
|
1424
1424
|
const commands = UnderpostWireguard.API.syncCommands({
|
|
1425
1425
|
repoEngine: 'https://github.com/underpostnet/engine.git',
|
|
1426
1426
|
}).map((step) => step.command);
|
|
1427
|
-
expect(commands).to.include('
|
|
1427
|
+
expect(commands).to.include('node bin cmt --switch-repo underpostnet/engine --target-branch master');
|
|
1428
1428
|
expect(commands).to.include(
|
|
1429
|
-
'
|
|
1429
|
+
'node bin cmt ./engine-private --switch-repo underpostnet/engine-private --target-branch main',
|
|
1430
1430
|
);
|
|
1431
1431
|
});
|
|
1432
1432
|
|
|
@@ -1436,9 +1436,9 @@ describe('engine sync', () => {
|
|
|
1436
1436
|
repoEngine: 'https://github.com/underpostnet/engine.git',
|
|
1437
1437
|
repoEnginePrivate: 'https://github.com/underposnet/engine-core-private.git',
|
|
1438
1438
|
}).map((step) => step.command);
|
|
1439
|
-
expect(commands).to.include('
|
|
1439
|
+
expect(commands).to.include('node bin cmt --switch-repo underpostnet/engine --target-branch master');
|
|
1440
1440
|
expect(commands).to.include(
|
|
1441
|
-
'
|
|
1441
|
+
'node bin cmt ./engine-private --switch-repo underposnet/engine-core-private --target-branch main',
|
|
1442
1442
|
);
|
|
1443
1443
|
});
|
|
1444
1444
|
|
|
@@ -1447,7 +1447,7 @@ describe('engine sync', () => {
|
|
|
1447
1447
|
const commands = UnderpostWireguard.API.syncCommands({ cmd: 'uptime, hostname -I' }).map((step) => step.command);
|
|
1448
1448
|
expect(commands).to.deep.equal(['uptime', 'hostname -I']);
|
|
1449
1449
|
expect(commands.join('\n')).to.not.match(/<[a-z-]+>/);
|
|
1450
|
-
expect(commands).to.not.include('
|
|
1450
|
+
expect(commands).to.not.include('node bin cmt --switch-repo');
|
|
1451
1451
|
});
|
|
1452
1452
|
|
|
1453
1453
|
it('labels a --cmd fleet run as a command, not a sync', () => {
|
|
@@ -1462,7 +1462,7 @@ describe('engine sync', () => {
|
|
|
1462
1462
|
process.env.GITHUB_USERNAME = 'someone';
|
|
1463
1463
|
Underpost.repo.getDefaultBranch = () => 'trunk';
|
|
1464
1464
|
expect(UnderpostWireguard.API.syncCommands().map((step) => step.command)).to.include(
|
|
1465
|
-
'
|
|
1465
|
+
'node bin cmt --switch-repo someone/engine --target-branch trunk',
|
|
1466
1466
|
);
|
|
1467
1467
|
});
|
|
1468
1468
|
|
|
@@ -1542,10 +1542,10 @@ describe('engine sync', () => {
|
|
|
1542
1542
|
const at = (command) => commands.indexOf(command);
|
|
1543
1543
|
|
|
1544
1544
|
expect(at('node bin host set ENGINE_SRC_REPO underpostnet/engine-test-cyberia')).to.be.greaterThan(
|
|
1545
|
-
at('
|
|
1545
|
+
at('node bin cmt --switch-repo underpostnet/engine-test-cyberia --target-branch master'),
|
|
1546
1546
|
);
|
|
1547
1547
|
expect(at('node bin host set ENGINE_SRC_PRIVATE_REPO underpostnet/engine-cyberia-private')).to.be.greaterThan(
|
|
1548
|
-
at('
|
|
1548
|
+
at('node bin cmt --switch-repo underpostnet/engine-test-cyberia --target-branch master'),
|
|
1549
1549
|
);
|
|
1550
1550
|
});
|
|
1551
1551
|
|
|
@@ -1563,23 +1563,63 @@ describe('engine sync', () => {
|
|
|
1563
1563
|
});
|
|
1564
1564
|
|
|
1565
1565
|
it.skipIf(!shipsCyberiaPackageScript)(
|
|
1566
|
-
'runs a deploy package script
|
|
1566
|
+
'runs a deploy package script when the deploy ships one, and installs the checkout when it does not',
|
|
1567
1567
|
() => {
|
|
1568
1568
|
process.env.GITHUB_USERNAME = 'someone';
|
|
1569
1569
|
const scripts = (repoEngine) =>
|
|
1570
|
-
UnderpostWireguard.API.syncCommands({ repoEngine })
|
|
1570
|
+
UnderpostWireguard.API.syncCommands({ repoEngine })
|
|
1571
|
+
.filter((step) => step.command.startsWith('bash '))
|
|
1572
|
+
.map((step) => step.command);
|
|
1571
1573
|
|
|
1572
|
-
|
|
1573
|
-
// rather than a missing install.
|
|
1574
|
-
expect(scripts('underpostnet/engine-test-cyberia').map((step) => step.command)).to.deep.equal([
|
|
1575
|
-
'bash ./deploy/dd-cyberia/package.sh',
|
|
1576
|
-
'bash ./deploy/dd-cyberia/package.sh',
|
|
1577
|
-
]);
|
|
1574
|
+
expect(scripts('underpostnet/engine-test-cyberia')).to.deep.equal(['bash ./deploy/dd-cyberia/package.sh']);
|
|
1578
1575
|
expect(scripts('underpostnet/engine-test-absent')).to.deep.equal([]);
|
|
1579
1576
|
expect(scripts('underpostnet/engine')).to.deep.equal([]);
|
|
1577
|
+
|
|
1578
|
+
// A sync that belongs to no deploy still lands new source, so the install is never dropped
|
|
1579
|
+
// — it falls back to the checkout's own manifest rather than leaving none.
|
|
1580
|
+
const commands = (repoEngine) => UnderpostWireguard.API.syncCommands({ repoEngine }).map((step) => step.command);
|
|
1581
|
+
expect(commands('underpostnet/engine')).to.include('npm install');
|
|
1582
|
+
expect(commands('underpostnet/engine-test-cyberia')).to.not.include('npm install');
|
|
1580
1583
|
},
|
|
1581
1584
|
);
|
|
1582
1585
|
|
|
1586
|
+
it('installs after the source switch with no CLI step in between', () => {
|
|
1587
|
+
process.env.GITHUB_USERNAME = 'someone';
|
|
1588
|
+
// Regression: the conf switch sat between the source switch and the install, so it ran the
|
|
1589
|
+
// freshly landed source against the previous `node_modules` and died importing a dependency
|
|
1590
|
+
// that switch had just added. Every step here is the node's own CLI, so none of them may
|
|
1591
|
+
// observe a checkout whose packages predate it.
|
|
1592
|
+
for (const repoEngine of ['underpostnet/engine', 'underpostnet/engine-test-cyberia']) {
|
|
1593
|
+
const commands = UnderpostWireguard.API.syncCommands({ repoEngine, nodeRole: 'control' }).map(
|
|
1594
|
+
(step) => step.command,
|
|
1595
|
+
);
|
|
1596
|
+
const switchAt = commands.findIndex(
|
|
1597
|
+
(command) => command.startsWith('node bin cmt --switch-repo') && !command.includes('./engine-private'),
|
|
1598
|
+
);
|
|
1599
|
+
const installAt = commands.findIndex(
|
|
1600
|
+
(command, index) => index > switchAt && (command.startsWith('bash ') || command === 'npm install'),
|
|
1601
|
+
);
|
|
1602
|
+
|
|
1603
|
+
expect(switchAt, repoEngine).to.be.greaterThan(-1);
|
|
1604
|
+
expect(installAt, repoEngine).to.equal(switchAt + 1);
|
|
1605
|
+
// The conf switch has to precede it, since the install reads the manifest that switch lands.
|
|
1606
|
+
expect(
|
|
1607
|
+
commands.findIndex((command) => command.includes('./engine-private --switch-repo')),
|
|
1608
|
+
repoEngine,
|
|
1609
|
+
).to.be.lessThan(switchAt);
|
|
1610
|
+
}
|
|
1611
|
+
});
|
|
1612
|
+
|
|
1613
|
+
it('restores the checkout manifest before the bootstrap install', () => {
|
|
1614
|
+
process.env.GITHUB_USERNAME = 'someone';
|
|
1615
|
+
// A previous sync left the deploy manifest copied over ./package.json, so installing without
|
|
1616
|
+
// restoring it reinstalls the previous scope and leaves the CLI unable to load new source.
|
|
1617
|
+
const commands = UnderpostWireguard.API.syncCommands().map((step) => step.command);
|
|
1618
|
+
expect(commands[0]).to.equal('git checkout -- package.json; npm install');
|
|
1619
|
+
// Sequenced, not chained: a tree that is not a repository still has to reach the install.
|
|
1620
|
+
expect(commands[0]).to.not.include('&&');
|
|
1621
|
+
});
|
|
1622
|
+
|
|
1583
1623
|
it('neutralizes advisory steps in place and chains the rest', () => {
|
|
1584
1624
|
process.env.GITHUB_USERNAME = 'someone';
|
|
1585
1625
|
const script = UnderpostWireguard.API.syncScript();
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
// Named import: js-yaml's ESM build exports no default.
|
|
6
|
+
import { load } from 'js-yaml';
|
|
7
|
+
import {
|
|
8
|
+
MONGO_EXPRESS_BASE_URL,
|
|
9
|
+
MONGO_EXPRESS_IMAGE,
|
|
10
|
+
MONGO_EXPRESS_NAME,
|
|
11
|
+
MONGO_EXPRESS_NODE_PORT,
|
|
12
|
+
MONGO_EXPRESS_PORT,
|
|
13
|
+
MONGO_EXPRESS_SECRET_NAME,
|
|
14
|
+
MONGO_EXPRESS_SERVICE_NAME,
|
|
15
|
+
mongoAuthEnabledFactory,
|
|
16
|
+
mongoExpressManifestPathFactory,
|
|
17
|
+
mongoExpressNodePortManifestFactory,
|
|
18
|
+
parseMongodArgs,
|
|
19
|
+
} from '../../../../src/db/mongo/MongoExpress.js';
|
|
20
|
+
|
|
21
|
+
const MONGODB_AUTH_ARGS = load(fs.readFileSync('./manifests/mongodb/statefulset.yaml', 'utf8')).spec.template.spec
|
|
22
|
+
.containers[0].args;
|
|
23
|
+
const MONGODB_4_4_ARGS = load(fs.readFileSync('./manifests/mongodb-4.4/statefulset.yaml', 'utf8')).spec.template.spec
|
|
24
|
+
.containers[0].args;
|
|
25
|
+
|
|
26
|
+
const readYaml = (path) => load(fs.readFileSync(path, 'utf8'));
|
|
27
|
+
const manifestDir = (authEnabled) => mongoExpressManifestPathFactory({ authEnabled });
|
|
28
|
+
const container = (deployment) => deployment.spec.template.spec.containers[0];
|
|
29
|
+
const envEntry = (deployment, name) => container(deployment).env.find((entry) => entry.name === name);
|
|
30
|
+
|
|
31
|
+
describe('mongo-express auth mode selection', () => {
|
|
32
|
+
it('reads authentication from the deployed statefulset, not from the invocation flags', () => {
|
|
33
|
+
// The set that is running decides, whichever flag this invocation carries.
|
|
34
|
+
expect(mongoAuthEnabledFactory({ args: MONGODB_AUTH_ARGS, options: { mongodb4: true } })).to.equal(true);
|
|
35
|
+
expect(mongoAuthEnabledFactory({ args: MONGODB_4_4_ARGS, options: { mongodb: true } })).to.equal(false);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('falls back to the flags only when no statefulset is deployed', () => {
|
|
39
|
+
expect(mongoAuthEnabledFactory({ args: null, options: { mongodb4: true } })).to.equal(false);
|
|
40
|
+
expect(mongoAuthEnabledFactory({ args: null, options: { mongodb: true } })).to.equal(true);
|
|
41
|
+
expect(mongoAuthEnabledFactory({})).to.equal(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('separates an undeployed statefulset from one that declares no arguments', () => {
|
|
45
|
+
expect(parseMongodArgs('')).to.equal(null);
|
|
46
|
+
expect(parseMongodArgs(' ')).to.equal(null);
|
|
47
|
+
expect(parseMongodArgs('mongodb|--replSet|rs0|--auth|')).to.deep.equal(['--replSet', 'rs0', '--auth']);
|
|
48
|
+
// An empty vector is a deployed server running on its defaults: no --auth, so no credentials,
|
|
49
|
+
// and the flags of this invocation do not get to overrule it.
|
|
50
|
+
expect(mongoAuthEnabledFactory({ args: parseMongodArgs('mongodb|'), options: { mongodb: true } })).to.equal(false);
|
|
51
|
+
expect(mongoAuthEnabledFactory({ args: parseMongodArgs(''), options: { mongodb: true } })).to.equal(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('routes each auth mode to a kustomization that exists', () => {
|
|
55
|
+
for (const authEnabled of [true, false]) {
|
|
56
|
+
const path = manifestDir(authEnabled);
|
|
57
|
+
expect(fs.existsSync(`${path}/kustomization.yaml`), path).to.equal(true);
|
|
58
|
+
}
|
|
59
|
+
expect(manifestDir(true)).to.not.equal(manifestDir(false));
|
|
60
|
+
expect(mongoExpressManifestPathFactory({ underpostRoot: '/npm/underpost', authEnabled: true })).to.equal(
|
|
61
|
+
'/npm/underpost/manifests/deployment/mongo-express',
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('mongo-express manifests', () => {
|
|
67
|
+
const base = manifestDir(true);
|
|
68
|
+
const deployment = readYaml(`${base}/deployment.yaml`);
|
|
69
|
+
const service = readYaml(`${base}/service.yaml`);
|
|
70
|
+
const kustomization = readYaml(`${base}/kustomization.yaml`);
|
|
71
|
+
|
|
72
|
+
it('projects both credential pairs from the statefulset secret', () => {
|
|
73
|
+
// The client owns no credential of its own: the same secret the StatefulSet consumes gates
|
|
74
|
+
// the mongod connection and the UI session.
|
|
75
|
+
for (const name of [
|
|
76
|
+
'ME_CONFIG_MONGODB_ADMINUSERNAME',
|
|
77
|
+
'ME_CONFIG_MONGODB_ADMINPASSWORD',
|
|
78
|
+
'ME_CONFIG_BASICAUTH_USERNAME',
|
|
79
|
+
'ME_CONFIG_BASICAUTH_PASSWORD',
|
|
80
|
+
]) {
|
|
81
|
+
const entry = envEntry(deployment, name);
|
|
82
|
+
expect(entry, name).to.be.an('object');
|
|
83
|
+
expect(entry.value, name).to.equal(undefined);
|
|
84
|
+
expect(entry.valueFrom.secretKeyRef.name, name).to.equal(MONGO_EXPRESS_SECRET_NAME);
|
|
85
|
+
expect(entry.valueFrom.secretKeyRef.key, name).to.be.oneOf(['username', 'password']);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('targets the in-cluster statefulset identity, which is identical under kind, kubeadm and k3s', () => {
|
|
90
|
+
expect(envEntry(deployment, 'ME_CONFIG_MONGODB_SERVER').value).to.equal('mongodb-0.mongodb-service');
|
|
91
|
+
expect(envEntry(deployment, 'ME_CONFIG_MONGODB_PORT').value).to.equal('27017');
|
|
92
|
+
expect(envEntry(deployment, 'ME_CONFIG_MONGODB_ENABLE_ADMIN').value).to.equal('true');
|
|
93
|
+
// The deploy surface reports the URL operators open; the manifest decides what it is.
|
|
94
|
+
expect(envEntry(deployment, 'ME_CONFIG_SITE_BASEURL').value).to.equal(MONGO_EXPRESS_BASE_URL);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('pins the image the pull path preloads', () => {
|
|
98
|
+
expect(container(deployment).image).to.equal(MONGO_EXPRESS_IMAGE);
|
|
99
|
+
expect(MONGO_EXPRESS_IMAGE).to.match(/:.+$/);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('keeps the service names and ports the deploy surface reports', () => {
|
|
103
|
+
expect(deployment.metadata.name).to.equal(MONGO_EXPRESS_NAME);
|
|
104
|
+
expect(service.metadata.name).to.equal(MONGO_EXPRESS_SERVICE_NAME);
|
|
105
|
+
expect(service.spec.type).to.equal('ClusterIP');
|
|
106
|
+
expect(service.spec.ports[0].port).to.equal(MONGO_EXPRESS_PORT);
|
|
107
|
+
expect(container(deployment).ports[0].containerPort).to.equal(MONGO_EXPRESS_PORT);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('leaves node exposure out of the kustomization', () => {
|
|
111
|
+
// An admin UI reaches the node network only through `--node-port`.
|
|
112
|
+
const nodePortManifest = mongoExpressNodePortManifestFactory({});
|
|
113
|
+
expect(kustomization.resources).to.deep.equal(['deployment.yaml', 'service.yaml']);
|
|
114
|
+
const nodePortService = readYaml(nodePortManifest);
|
|
115
|
+
expect(nodePortService.spec.type).to.equal('NodePort');
|
|
116
|
+
expect(nodePortService.spec.ports[0].nodePort).to.equal(MONGO_EXPRESS_NODE_PORT);
|
|
117
|
+
expect(nodePortService.spec.selector).to.deep.equal(deployment.spec.selector.matchLabels);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('drops only the credentials a no-auth mongod would reject', () => {
|
|
121
|
+
const overlay = manifestDir(false);
|
|
122
|
+
const overlayKustomization = readYaml(`${overlay}/kustomization.yaml`);
|
|
123
|
+
expect(overlayKustomization.resources).to.deep.equal(['../mongo-express']);
|
|
124
|
+
const patchPath = `${overlay}/${overlayKustomization.patches[0].path}`;
|
|
125
|
+
const deleted = readYaml(patchPath)
|
|
126
|
+
.spec.template.spec.containers[0].env.filter((entry) => entry.$patch === 'delete')
|
|
127
|
+
.map((entry) => entry.name);
|
|
128
|
+
expect(deleted).to.deep.equal([
|
|
129
|
+
'ME_CONFIG_MONGODB_ADMINUSERNAME',
|
|
130
|
+
'ME_CONFIG_MONGODB_ADMINPASSWORD',
|
|
131
|
+
'ME_CONFIG_MONGODB_AUTH_DATABASE',
|
|
132
|
+
]);
|
|
133
|
+
// The UI session stays gated: dropping the server credentials must not publish the client.
|
|
134
|
+
expect(deleted).to.not.include('ME_CONFIG_BASICAUTH_USERNAME');
|
|
135
|
+
expect(deleted).to.not.include('ME_CONFIG_BASICAUTH_PASSWORD');
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('mongo-express cluster wiring', () => {
|
|
140
|
+
const clusterSource = fs.readFileSync('./src/cli/cluster.js', 'utf8');
|
|
141
|
+
|
|
142
|
+
it('registers the flag on the cluster command', () => {
|
|
143
|
+
expect(fs.readFileSync('./src/cli/index.js', 'utf8')).to.include("'--mongo-express'");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('deploys the client after the statefulset branches', () => {
|
|
147
|
+
expect(clusterSource).to.include('if (options.mongoExpress)');
|
|
148
|
+
expect(clusterSource.indexOf('options.mongoExpress')).to.be.greaterThan(clusterSource.indexOf('options.mongodb4'));
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('keeps one deploy path shared with the service runner', () => {
|
|
152
|
+
const runSource = fs.readFileSync('./src/cli/run.js', 'utf8');
|
|
153
|
+
expect(runSource).to.include('MongoExpress.deploy(');
|
|
154
|
+
expect(runSource).to.not.include('manifests/deployment/mongo-express/deployment.yaml');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
import {
|
|
5
|
+
buildCrudController,
|
|
6
|
+
serviceHandler,
|
|
7
|
+
setCrossOriginHeaders,
|
|
8
|
+
} from '../../../../src/server/network/middlewares.js';
|
|
9
|
+
|
|
10
|
+
// Minimal Express doubles: the middleware only sets headers and sends one JSON envelope.
|
|
11
|
+
const requestFrom = (origin) => ({ query: {}, params: {}, path: '/', headers: origin ? { origin } : {} });
|
|
12
|
+
const responseSpy = () => {
|
|
13
|
+
const headers = {};
|
|
14
|
+
const response = {
|
|
15
|
+
headers,
|
|
16
|
+
body: undefined,
|
|
17
|
+
statusCode: 0,
|
|
18
|
+
set: (key, value) => (headers[key] = value),
|
|
19
|
+
setHeader: (key, value) => (headers[key] = value),
|
|
20
|
+
status(code) {
|
|
21
|
+
this.statusCode = code;
|
|
22
|
+
return this;
|
|
23
|
+
},
|
|
24
|
+
json(body) {
|
|
25
|
+
this.body = body;
|
|
26
|
+
return this;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
return response;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const crudService = {
|
|
33
|
+
get: async () => ({ data: [], total: 0 }),
|
|
34
|
+
post: async () => ({}),
|
|
35
|
+
put: async () => ({}),
|
|
36
|
+
delete: async () => ({}),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
describe('public API cross-origin policy', () => {
|
|
40
|
+
it('answers a browser read with the origin it came from', async () => {
|
|
41
|
+
// The browser client is served from its own origin: a read without this header arrives with
|
|
42
|
+
// status 200 and is then discarded by the same-origin policy, which looks like a broken
|
|
43
|
+
// feature rather than a failed request.
|
|
44
|
+
const response = responseSpy();
|
|
45
|
+
await buildCrudController(crudService).get(requestFrom('http://localhost:8082'), response, {});
|
|
46
|
+
expect(response.headers['Access-Control-Allow-Origin']).to.equal('http://localhost:8082');
|
|
47
|
+
expect(response.headers['Cross-Origin-Resource-Policy']).to.equal('cross-origin');
|
|
48
|
+
expect(response.statusCode).to.equal(200);
|
|
49
|
+
expect(response.body.status).to.equal('success');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('falls back to any origin when the request declares none', async () => {
|
|
53
|
+
const response = responseSpy();
|
|
54
|
+
await buildCrudController(crudService).get(requestFrom(), response, {});
|
|
55
|
+
expect(response.headers['Access-Control-Allow-Origin']).to.equal('*');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('keeps writes same-origin: only reads are public', async () => {
|
|
59
|
+
const response = responseSpy();
|
|
60
|
+
await buildCrudController(crudService).post(requestFrom('http://localhost:8082'), response, {});
|
|
61
|
+
expect(response.headers).to.not.have.property('Access-Control-Allow-Origin');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('carries the same policy on a hand-written read handler', async () => {
|
|
65
|
+
// `setCrossOriginHeaders` is the one place the policy lives, so a custom route opts in with it
|
|
66
|
+
// rather than restating the headers.
|
|
67
|
+
const response = responseSpy();
|
|
68
|
+
await serviceHandler(async () => ({ ok: true }), { crossOrigin: true })(
|
|
69
|
+
requestFrom('https://www.cyberiaonline.com'),
|
|
70
|
+
response,
|
|
71
|
+
{},
|
|
72
|
+
);
|
|
73
|
+
expect(response.headers['Access-Control-Allow-Origin']).to.equal('https://www.cyberiaonline.com');
|
|
74
|
+
|
|
75
|
+
const direct = responseSpy();
|
|
76
|
+
setCrossOriginHeaders(requestFrom('https://www.cyberiaonline.com'), direct);
|
|
77
|
+
expect(direct.headers).to.deep.equal(response.headers);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -263,7 +263,7 @@ describe('shared ingress front', () => {
|
|
|
263
263
|
);
|
|
264
264
|
const testCandidate = install.indexOf("execIngress('nginx -t -c /tmp/nginx.candidate.conf'");
|
|
265
265
|
const reload = install.indexOf('nginx -s reload -c /tmp/nginx.conf', testCandidate);
|
|
266
|
-
const persist = install.indexOf("
|
|
266
|
+
const persist = install.indexOf("`kubectl apply -f - -n ${namespace} <<'EOF'", reload);
|
|
267
267
|
expect(testCandidate).to.be.greaterThan(-1);
|
|
268
268
|
expect(reload).to.be.greaterThan(testCandidate);
|
|
269
269
|
expect(persist).to.be.greaterThan(reload);
|
|
@@ -14,6 +14,12 @@ import { TEST_TIERS } from '../../src/server/build/testing.js';
|
|
|
14
14
|
const catalogs = await loadProductCatalogs();
|
|
15
15
|
const describeProducts = describe.skipIf(catalogs.length === 0);
|
|
16
16
|
|
|
17
|
+
// A product template keeps its own catalog but has every other product sliced away, so only
|
|
18
|
+
// the unsliced engine tree carries every catalog and every tier directory. `buildTemplate`
|
|
19
|
+
// drops `build:template` from the manifest and every product manifest inherits that, which
|
|
20
|
+
// makes the script the one durable marker of the unsliced tree.
|
|
21
|
+
const unsliced = !!JSON.parse(fs.readFileSync('./package.json', 'utf8')).scripts?.['build:template'];
|
|
22
|
+
|
|
17
23
|
describeProducts('product catalogs', () => {
|
|
18
24
|
it('every catalog carries the uniform shape', () => {
|
|
19
25
|
for (const catalog of catalogs)
|
|
@@ -54,14 +60,19 @@ describeProducts('product catalogs and the test tiers', () => {
|
|
|
54
60
|
catalogs.some(({ stripPaths }) => stripPaths.includes(`./${directory}`)),
|
|
55
61
|
);
|
|
56
62
|
|
|
57
|
-
it('has products that own at least one tier', () => {
|
|
63
|
+
it.skipIf(!unsliced)('has products that own at least one tier', () => {
|
|
58
64
|
expect(strippedTiers).to.not.be.empty;
|
|
59
65
|
});
|
|
60
66
|
|
|
61
|
-
it('gives every tier a directory that exists in an unsliced tree', () => {
|
|
67
|
+
it.skipIf(!unsliced)('gives every tier a directory that exists in an unsliced tree', () => {
|
|
62
68
|
for (const { name, directory } of TEST_TIERS) expect(fs.existsSync(directory), name).to.equal(true);
|
|
63
69
|
});
|
|
64
70
|
|
|
71
|
+
it('carries the directory of every tier a present product owns', () => {
|
|
72
|
+
// Holds in a product template too: what it kept of itself must be whole.
|
|
73
|
+
for (const { name, directory } of strippedTiers) expect(fs.existsSync(directory), name).to.equal(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
65
76
|
it('ships every tier it strips from the base template', () => {
|
|
66
77
|
for (const { name, directory } of strippedTiers) {
|
|
67
78
|
const owner = catalogs.find(({ stripPaths }) => stripPaths.includes(`./${directory}`));
|