@underpostnet/cyberia 3.2.90 → 3.3.0
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 +16 -0
- package/.github/workflows/coverall.cyberia.ci.yml +87 -0
- package/.github/workflows/cyberia-client.cd.yml +1 -18
- package/.github/workflows/cyberia-server.cd.yml +1 -18
- 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.cd.yml +3 -78
- package/.github/workflows/ghpkg.ci.yml +7 -1
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -16
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +1 -9
- package/CHANGELOG.md +110 -1
- package/CLI-HELP.md +139 -9
- package/Dockerfile +1 -1
- package/Dockerfile.dev +1 -1
- package/Dockerfile.test +1 -1
- package/bin/build.js +7 -5
- package/bin/cyberia.js +73 -53
- package/bin/deploy.js +1 -1
- package/bin/index.js +73 -53
- package/compose.env +16 -0
- package/conf.js +2 -0
- package/deploy/dd-cyberia/deploy.sh +42 -0
- package/deploy/dd-cyberia/init.sh +63 -0
- package/deploy/dd-cyberia/sync-deploy.sh +194 -0
- package/deploy/lib/logging.sh +96 -0
- package/deploy/pwa-microservices-template/deploy.sh +72 -0
- package/deploy/release/deploy.sh +62 -0
- package/deployment.yaml +1 -1
- package/docker-compose.yml +31 -37
- package/hardhat/package-lock.json +9 -9
- package/hardhat/package.json +3 -3
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +5 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +52 -0
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/package.json +2 -2
- package/scripts/audit-selinux.sh +64 -0
- package/scripts/coverall-test-cyberia.sh +24 -0
- package/scripts/coverall-test.sh +24 -0
- package/scripts/gpu-diag.sh +0 -0
- package/scripts/ip-info.sh +0 -0
- package/scripts/k3s-node-setup.sh +18 -15
- package/scripts/kubeadm-node-setup.sh +12 -23
- package/scripts/link-local-underpost-cli.sh +0 -0
- package/scripts/lxd-vm-setup.sh +0 -0
- package/scripts/maas-nat-firewalld.sh +0 -0
- package/scripts/nat-iptables.sh +2 -0
- package/scripts/rhel-grpc-setup.sh +0 -0
- package/scripts/rocky-kickstart.sh +25 -9
- package/scripts/test-monitor.sh +1 -1
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +63 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +8 -1
- package/src/api/cyberia-instance/cyberia-instance.controller.js +3 -0
- package/src/api/cyberia-instance/cyberia-instance.router.js +13 -0
- package/src/api/cyberia-instance/cyberia-instance.service.js +43 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +1 -0
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +16 -3
- package/src/api/object-layer/object-layer.model.js +204 -3
- package/src/api/object-layer/object-layer.service.js +1 -14
- package/src/cli/baremetal.js +1 -2
- package/src/cli/cloud-init.js +1 -1
- package/src/cli/cluster.js +73 -68
- package/src/cli/db.js +9 -2
- package/src/cli/deploy.js +21 -5
- package/src/cli/docker-compose.js +1 -1
- package/src/cli/env.js +1 -1
- package/src/cli/image.js +0 -1
- package/src/cli/index.js +121 -9
- package/src/cli/lxd.js +1 -1
- package/src/cli/monitor.js +1 -1
- package/src/cli/release.js +57 -22
- package/src/cli/repository.js +11 -9
- package/src/cli/run.js +36 -9
- package/src/cli/ssh.js +198 -77
- package/src/cli/system.js +26 -13
- package/src/cli/test.js +1 -1
- package/src/cli/vultr.js +583 -0
- package/src/cli/wireguard.js +2125 -0
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +368 -0
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +33 -0
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +4 -0
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +17 -3
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +1 -1
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +40 -0
- package/src/client/services/object-layer/object-layer.management.js +4 -4
- package/src/client-builder/client-build.js +20 -14
- package/src/db/mongo/MongooseDB.js +4 -0
- package/src/index.js +25 -1
- package/src/projects/cyberia/catalog-cyberia.js +5 -0
- package/src/projects/cyberia/generate-saga.js +14 -23
- package/src/projects/cyberia/instance-data.js +21 -2
- package/src/projects/cyberia/object-layer.js +11 -21
- package/src/projects/underpost/catalog-underpost.js +4 -1
- package/src/runtime/cyberia-client/Dockerfile +1 -1
- package/src/runtime/cyberia-client/Dockerfile.dev +1 -1
- package/src/runtime/cyberia-server/Dockerfile +1 -1
- package/src/runtime/cyberia-server/Dockerfile.dev +1 -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 +1 -1
- package/src/runtime/engine-cyberia/compose.env +16 -0
- package/src/runtime/engine-cyberia/docker-compose.yml +31 -37
- package/src/server/backup.js +1 -1
- package/src/server/conf.js +18 -108
- package/src/server/cron.js +249 -51
- package/src/server/dns.js +100 -6
- package/src/server/environment.js +98 -0
- package/src/server/forward-proxy.js +549 -0
- package/src/server/middlewares.js +56 -1
- package/src/server/process.js +0 -1
- package/src/server/selinux.js +185 -0
- package/src/server/systemd.js +205 -0
- package/src/server/underpost-compression.js +186 -0
- package/src/server/underpost-gateway.js +20 -10
- package/src/server/underpost-ingress.js +18 -2
- package/test/cyberia-instance-conf-defaults.test.js +1 -0
- package/test/selinux.test.js +71 -0
- package/test/underpost-gateway.test.js +41 -0
- package/test/underpost-ingress.test.js +52 -0
- package/test/wireguard-edge.test.js +1177 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
apiVersion: batch/v1
|
|
2
|
+
kind: CronJob
|
|
3
|
+
metadata:
|
|
4
|
+
name: dd-cron-vultr
|
|
5
|
+
namespace: default
|
|
6
|
+
labels:
|
|
7
|
+
app: dd-cron-vultr
|
|
8
|
+
managed-by: underpost
|
|
9
|
+
spec:
|
|
10
|
+
schedule: "*/30 * * * *"
|
|
11
|
+
concurrencyPolicy: Forbid
|
|
12
|
+
startingDeadlineSeconds: 200
|
|
13
|
+
successfulJobsHistoryLimit: 3
|
|
14
|
+
failedJobsHistoryLimit: 1
|
|
15
|
+
suspend: false
|
|
16
|
+
jobTemplate:
|
|
17
|
+
metadata:
|
|
18
|
+
labels:
|
|
19
|
+
app: dd-cron-vultr
|
|
20
|
+
managed-by: underpost
|
|
21
|
+
spec:
|
|
22
|
+
template:
|
|
23
|
+
metadata:
|
|
24
|
+
labels:
|
|
25
|
+
app: dd-cron-vultr
|
|
26
|
+
managed-by: underpost
|
|
27
|
+
spec:
|
|
28
|
+
containers:
|
|
29
|
+
- name: dd-cron-vultr
|
|
30
|
+
image: underpost/underpost-engine:v3.3.0
|
|
31
|
+
command:
|
|
32
|
+
- /bin/sh
|
|
33
|
+
- -c
|
|
34
|
+
- >
|
|
35
|
+
cd /home/dd/engine &&
|
|
36
|
+
node bin env dd-cron production &&
|
|
37
|
+
node bin cron dd-cron vultr --git --kubeadm
|
|
38
|
+
volumeMounts:
|
|
39
|
+
- mountPath: /home/dd/engine
|
|
40
|
+
name: underpost-cron-container-volume
|
|
41
|
+
- mountPath: /usr/lib/node_modules/underpost
|
|
42
|
+
name: underpost-share-env
|
|
43
|
+
volumes:
|
|
44
|
+
- hostPath:
|
|
45
|
+
path: /home/dd/engine
|
|
46
|
+
type: Directory
|
|
47
|
+
name: underpost-cron-container-volume
|
|
48
|
+
- hostPath:
|
|
49
|
+
path: /root/.nvm/versions/node/v24.15.0/lib/node_modules/underpost
|
|
50
|
+
type: DirectoryOrCreate
|
|
51
|
+
name: underpost-share-env
|
|
52
|
+
restartPolicy: OnFailure
|
|
@@ -17,7 +17,7 @@ spec:
|
|
|
17
17
|
spec:
|
|
18
18
|
containers:
|
|
19
19
|
- name: dd-default-development-blue
|
|
20
|
-
image: underpost/underpost-engine:v3.
|
|
20
|
+
image: underpost/underpost-engine:v3.3.0
|
|
21
21
|
# resources:
|
|
22
22
|
# requests:
|
|
23
23
|
# memory: "124Ki"
|
|
@@ -98,7 +98,7 @@ spec:
|
|
|
98
98
|
spec:
|
|
99
99
|
containers:
|
|
100
100
|
- name: dd-default-development-green
|
|
101
|
-
image: underpost/underpost-engine:v3.
|
|
101
|
+
image: underpost/underpost-engine:v3.3.0
|
|
102
102
|
# resources:
|
|
103
103
|
# requests:
|
|
104
104
|
# memory: "124Ki"
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"type": "module",
|
|
3
3
|
"main": "src/index.js",
|
|
4
4
|
"name": "@underpostnet/cyberia",
|
|
5
|
-
"version": "3.
|
|
5
|
+
"version": "3.3.0",
|
|
6
6
|
"description": "Cyberia CLI — toolchain for the Cyberia MMO data layer, content pipeline, persistence, gRPC services, and ERC-1155 lifecycle on Hyperledger Besu.",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "node --max-old-space-size=8192 src/server",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
},
|
|
73
73
|
"homepage": "https://github.com/underpostnet/engine-cyberia#readme",
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"underpost": "^3.
|
|
75
|
+
"underpost": "^3.3.0",
|
|
76
76
|
"adm-zip": "^0.6.0",
|
|
77
77
|
"maxrects-packer": "^2.7.3",
|
|
78
78
|
"pngjs": "^7.0.0",
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SINCE="recent"
|
|
5
|
+
FAIL_ON_AVC="1"
|
|
6
|
+
|
|
7
|
+
while [ "$#" -gt 0 ]; do
|
|
8
|
+
case "$1" in
|
|
9
|
+
--since)
|
|
10
|
+
[ "$#" -ge 2 ] || { echo "--since requires an ausearch time value" >&2; exit 2; }
|
|
11
|
+
SINCE="$2"
|
|
12
|
+
shift 2
|
|
13
|
+
;;
|
|
14
|
+
--no-fail)
|
|
15
|
+
FAIL_ON_AVC="0"
|
|
16
|
+
shift
|
|
17
|
+
;;
|
|
18
|
+
-h|--help)
|
|
19
|
+
echo "Usage: $0 [--since recent|today|boot|TIME] [--no-fail]"
|
|
20
|
+
exit 0
|
|
21
|
+
;;
|
|
22
|
+
*)
|
|
23
|
+
echo "Unknown option: $1" >&2
|
|
24
|
+
exit 2
|
|
25
|
+
;;
|
|
26
|
+
esac
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
command -v getenforce >/dev/null 2>&1 || {
|
|
30
|
+
echo "SELinux userspace is unavailable. Install policycoreutils." >&2
|
|
31
|
+
exit 2
|
|
32
|
+
}
|
|
33
|
+
command -v ausearch >/dev/null 2>&1 || {
|
|
34
|
+
echo "ausearch is unavailable. Install audit and start auditd." >&2
|
|
35
|
+
exit 2
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
MODE="$(getenforce)"
|
|
39
|
+
echo "SELinux mode: $MODE"
|
|
40
|
+
[ "$MODE" = "Enforcing" ] || echo "WARNING: expected Enforcing mode" >&2
|
|
41
|
+
command -v sestatus >/dev/null 2>&1 && sestatus
|
|
42
|
+
|
|
43
|
+
AUDIT=(ausearch)
|
|
44
|
+
[ "$(id -u)" -eq 0 ] || AUDIT=(sudo ausearch)
|
|
45
|
+
RAW_FILE="$(mktemp /tmp/underpost-selinux-avc.XXXXXX)"
|
|
46
|
+
trap 'rm -f "$RAW_FILE"' EXIT
|
|
47
|
+
|
|
48
|
+
"${AUDIT[@]}" -m AVC,USER_AVC,SELINUX_ERR -ts "$SINCE" --raw > "$RAW_FILE" 2>/dev/null || true
|
|
49
|
+
if ! grep -q '^type=' "$RAW_FILE"; then
|
|
50
|
+
echo "No SELinux AVC denials found since: $SINCE"
|
|
51
|
+
[ "$MODE" = "Enforcing" ]
|
|
52
|
+
exit
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
echo "SELinux AVC denials found since: $SINCE" >&2
|
|
56
|
+
"${AUDIT[@]}" -m AVC,USER_AVC,SELINUX_ERR -ts "$SINCE" -i || true
|
|
57
|
+
if command -v sealert >/dev/null 2>&1; then
|
|
58
|
+
echo "sealert analysis:"
|
|
59
|
+
sealert -a "$RAW_FILE" || true
|
|
60
|
+
else
|
|
61
|
+
echo "Install setroubleshoot-server for sealert analysis." >&2
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
[ "$FAIL_ON_AVC" = "0" ] || exit 1
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u -o pipefail
|
|
3
|
+
|
|
4
|
+
EXCLUDES=(
|
|
5
|
+
--exclude="test/cluster-instances.test.js"
|
|
6
|
+
--exclude="test/deploy-monitor.test.js"
|
|
7
|
+
--exclude="test/deploy-node-placement.test.js"
|
|
8
|
+
--exclude="test/instance-traffic-plan.test.js"
|
|
9
|
+
--exclude="test/sops-secret-store.test.js"
|
|
10
|
+
--exclude="test/underpost-gateway.test.js"
|
|
11
|
+
--exclude="test/underpost-ingress.test.js"
|
|
12
|
+
--exclude="test/wireguard-edge.test.js"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
TESTS=(
|
|
16
|
+
test/cyberia-instance-conf-defaults.test.js
|
|
17
|
+
test/cyberia-load.test.js
|
|
18
|
+
test/object-layer-item-id.test.js
|
|
19
|
+
test/api.test.js
|
|
20
|
+
test/crypto.test.js
|
|
21
|
+
test/shape-generator.test.js
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
c8 "${EXCLUDES[@]}" mocha "${TESTS[@]}"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u -o pipefail
|
|
3
|
+
|
|
4
|
+
EXCLUDES=(
|
|
5
|
+
--exclude="test/cyberia-instance-conf-defaults.test.js"
|
|
6
|
+
--exclude="test/cyberia-load.test.js"
|
|
7
|
+
--exclude="test/object-layer-item-id.test.js"
|
|
8
|
+
--exclude="test/api.test.js"
|
|
9
|
+
--exclude="test/crypto.test.js"
|
|
10
|
+
--exclude="test/shape-generator.test.js"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
TESTS=(
|
|
14
|
+
test/cluster-instances.test.js
|
|
15
|
+
test/deploy-monitor.test.js
|
|
16
|
+
test/deploy-node-placement.test.js
|
|
17
|
+
test/instance-traffic-plan.test.js
|
|
18
|
+
test/sops-secret-store.test.js
|
|
19
|
+
test/underpost-gateway.test.js
|
|
20
|
+
test/underpost-ingress.test.js
|
|
21
|
+
test/wireguard-edge.test.js
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
c8 "${EXCLUDES[@]}" mocha "${TESTS[@]}"
|
package/scripts/gpu-diag.sh
CHANGED
|
File without changes
|
package/scripts/ip-info.sh
CHANGED
|
File without changes
|
|
@@ -49,22 +49,25 @@ if [ -z "$(ls -A "$ENGINE_ROOT")" ]; then
|
|
|
49
49
|
fi
|
|
50
50
|
|
|
51
51
|
# ---------------------------------------------------------------------------
|
|
52
|
-
#
|
|
52
|
+
# System-wide Node.js is required by service units under SELinux.
|
|
53
53
|
# ---------------------------------------------------------------------------
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
|
|
59
|
-
# shellcheck disable=SC1090
|
|
60
|
-
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
54
|
+
if command -v dnf >/dev/null 2>&1; then
|
|
55
|
+
sudo dnf install -y policycoreutils policycoreutils-python-utils selinux-policy-targeted audit
|
|
56
|
+
fi
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
if ! command -v node >/dev/null 2>&1 || ! node --version 2>/dev/null | grep -q '^v24'; then
|
|
59
|
+
echo "Installing system-wide Node.js 24..."
|
|
60
|
+
if command -v dnf >/dev/null 2>&1; then
|
|
61
|
+
curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash -
|
|
62
|
+
sudo dnf install -y nodejs
|
|
63
|
+
elif command -v apt-get >/dev/null 2>&1; then
|
|
64
|
+
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo bash -
|
|
65
|
+
sudo apt-get install -y nodejs
|
|
66
|
+
else
|
|
67
|
+
echo "ERROR: a supported system package manager is required for Node.js 24" >&2
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
fi
|
|
68
71
|
|
|
69
72
|
echo "
|
|
70
73
|
██╗░░░██╗███╗░░██╗██████╗░███████╗██████╗░██████╗░░█████╗░░██████╗████████╗
|
|
@@ -116,7 +119,7 @@ if [ "$ROLE" = "control" ]; then
|
|
|
116
119
|
curl -sfL https://get.k3s.io | \
|
|
117
120
|
K3S_URL="https://${CONTROL_IP}:6443" \
|
|
118
121
|
K3S_TOKEN="${K3S_TOKEN}" \
|
|
119
|
-
sh -s - agent
|
|
122
|
+
sh -s - agent $(if command -v selinuxenabled >/dev/null 2>&1 && selinuxenabled; then printf '%s' '--selinux'; fi)
|
|
120
123
|
|
|
121
124
|
echo ""
|
|
122
125
|
echo "K3s worker joined https://${CONTROL_IP}:6443 successfully."
|
|
@@ -5,8 +5,8 @@ set -euo pipefail
|
|
|
5
5
|
# Underpost Kubeadm Node Setup (bare-metal physical node)
|
|
6
6
|
#
|
|
7
7
|
# Mirrors scripts/k3s-node-setup.sh but for kubeadm on real hardware: it runs on
|
|
8
|
-
# the freshly deployed OS (disk-installed Rocky) after first boot, installs
|
|
9
|
-
# Node.js, ensures the engine source is present, and drives the cluster bring-up
|
|
8
|
+
# the freshly deployed OS (disk-installed Rocky) after first boot, installs
|
|
9
|
+
# system-wide Node.js, ensures the engine source is present, and drives the cluster bring-up
|
|
10
10
|
# through the local engine entrypoint `node bin cluster` (src/cli/cluster.js) —
|
|
11
11
|
# reusing its kubeadm + Contour + host-init logic instead of reimplementing it.
|
|
12
12
|
#
|
|
@@ -146,33 +146,22 @@ if [ "$JOIN_ONLY" = "1" ]; then
|
|
|
146
146
|
fi
|
|
147
147
|
|
|
148
148
|
# ---------------------------------------------------------------------------
|
|
149
|
-
# 0. Base prerequisites
|
|
150
|
-
# NVM needs to extract Node.js and the engine clone needs. Install them first.
|
|
149
|
+
# 0. Base prerequisites.
|
|
151
150
|
# ---------------------------------------------------------------------------
|
|
152
|
-
log "Installing base prerequisites
|
|
153
|
-
sudo dnf install -y tar xz gzip bzip2 git curl ca-certificates which findutils 2>/dev/null \
|
|
154
|
-
|| dnf install -y tar xz gzip bzip2 git curl ca-certificates which findutils
|
|
151
|
+
log "Installing base prerequisites..."
|
|
152
|
+
sudo dnf install -y tar xz gzip bzip2 git curl ca-certificates which findutils policycoreutils policycoreutils-python-utils selinux-policy-targeted audit 2>/dev/null \
|
|
153
|
+
|| dnf install -y tar xz gzip bzip2 git curl ca-certificates which findutils policycoreutils policycoreutils-python-utils selinux-policy-targeted audit
|
|
155
154
|
|
|
156
155
|
# ---------------------------------------------------------------------------
|
|
157
|
-
# 1.
|
|
158
|
-
#
|
|
156
|
+
# 1. System-wide Node.js. Home-directory runtimes cannot be used by hardened
|
|
157
|
+
# systemd services under SELinux.
|
|
159
158
|
# ---------------------------------------------------------------------------
|
|
160
159
|
if command -v node >/dev/null 2>&1 && node --version 2>/dev/null | grep -q '^v24'; then
|
|
161
|
-
log "Node.js $(node --version) already installed
|
|
160
|
+
log "Node.js $(node --version) already installed"
|
|
162
161
|
else
|
|
163
|
-
log "Installing
|
|
164
|
-
curl -
|
|
165
|
-
|
|
166
|
-
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
|
|
167
|
-
# shellcheck disable=SC1090
|
|
168
|
-
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
169
|
-
|
|
170
|
-
nvm install 24.15.0
|
|
171
|
-
nvm use 24.15.0
|
|
172
|
-
nvm alias default 24.15.0
|
|
173
|
-
ln -sf "$(command -v node)" /usr/local/bin/node
|
|
174
|
-
ln -sf "$(command -v npm)" /usr/local/bin/npm
|
|
175
|
-
ln -sf "$(command -v npx)" /usr/local/bin/npx
|
|
162
|
+
log "Installing system-wide Node.js 24..."
|
|
163
|
+
curl -fsSL https://rpm.nodesource.com/setup_24.x | sudo bash -
|
|
164
|
+
sudo dnf install -y nodejs
|
|
176
165
|
fi
|
|
177
166
|
|
|
178
167
|
echo "
|
|
File without changes
|
package/scripts/lxd-vm-setup.sh
CHANGED
|
File without changes
|
|
File without changes
|
package/scripts/nat-iptables.sh
CHANGED
|
@@ -42,12 +42,14 @@ echo "[INFO] Opening Kubernetes control plane ports..."
|
|
|
42
42
|
|
|
43
43
|
# Kubernetes API Server
|
|
44
44
|
sudo firewall-cmd --permanent --zone=public --add-port=6443/tcp
|
|
45
|
+
sudo firewall-cmd --permanent --zone=public --add-port=6443/udp
|
|
45
46
|
|
|
46
47
|
# etcd
|
|
47
48
|
sudo firewall-cmd --permanent --zone=public --add-port=2379-2380/tcp
|
|
48
49
|
|
|
49
50
|
# kubelet API
|
|
50
51
|
sudo firewall-cmd --permanent --zone=public --add-port=10250/tcp
|
|
52
|
+
sudo firewall-cmd --permanent --zone=public --add-port=10250/udp
|
|
51
53
|
|
|
52
54
|
# kube-scheduler
|
|
53
55
|
sudo firewall-cmd --permanent --zone=public --add-port=10259/tcp
|
|
File without changes
|
|
@@ -168,7 +168,7 @@ PermitEmptyPasswords no
|
|
|
168
168
|
PasswordAuthentication ${SSHD_PASSWORD_AUTH}
|
|
169
169
|
ChallengeResponseAuthentication ${SSHD_KBD_INTERACTIVE}
|
|
170
170
|
KbdInteractiveAuthentication ${SSHD_KBD_INTERACTIVE}
|
|
171
|
-
UsePAM
|
|
171
|
+
UsePAM yes
|
|
172
172
|
X11Forwarding no
|
|
173
173
|
PrintMotd no
|
|
174
174
|
TCPKeepAlive yes
|
|
@@ -585,7 +585,7 @@ fi
|
|
|
585
585
|
post_status "installing" "\"detail\":\"installing packages\",\"disk\":\"\$REAL_DISK\""
|
|
586
586
|
|
|
587
587
|
ilog "Installing base packages with dnf --installroot ..."
|
|
588
|
-
PKGS="@core kernel grub2-tools openssh-server NetworkManager chrony dracut-config-generic rocky-release"
|
|
588
|
+
PKGS="@core kernel grub2-tools openssh-server NetworkManager chrony dracut-config-generic rocky-release policycoreutils policycoreutils-python-utils selinux-policy-targeted audit sudo"
|
|
589
589
|
if [ "\$FW" = "uefi" ]; then
|
|
590
590
|
PKGS="\$PKGS grub2-efi-x64 shim-x64 efibootmgr"
|
|
591
591
|
else
|
|
@@ -622,15 +622,10 @@ ilog "Configuring installed system (hostname, network, ssh, users) ..."
|
|
|
622
622
|
echo "\${TARGET_HOSTNAME:-rocky9}" > "\$TARGET_MNT/etc/hostname"
|
|
623
623
|
|
|
624
624
|
chroot "\$TARGET_MNT" /bin/bash -s << CHROOTEOF >> "\$KS_LOG" 2>&1
|
|
625
|
-
set
|
|
625
|
+
set -e
|
|
626
626
|
systemctl enable sshd NetworkManager chronyd 2>/dev/null
|
|
627
627
|
|
|
628
|
-
|
|
629
|
-
# first boot, files written from this installer chroot (authorized_keys, home
|
|
630
|
-
# dirs) carry the wrong security context, so sshd drops sessions ("Connection
|
|
631
|
-
# reset by peer") and PAM can block console logins. Permissive ignores contexts
|
|
632
|
-
# (no relabel reboot needed) and matches what kubeadm/cluster.js expect.
|
|
633
|
-
sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config 2>/dev/null || true
|
|
628
|
+
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
|
|
634
629
|
|
|
635
630
|
# Ensure sshd host keys exist so sshd actually starts on first boot.
|
|
636
631
|
ssh-keygen -A 2>/dev/null || true
|
|
@@ -708,11 +703,19 @@ fi
|
|
|
708
703
|
# Key-only SSH on the installed system.
|
|
709
704
|
mkdir -p /etc/ssh/sshd_config.d
|
|
710
705
|
cat > /etc/ssh/sshd_config.d/00-underpost.conf <<SSHDEOF
|
|
706
|
+
Port ${SSH_PORT}
|
|
711
707
|
PermitRootLogin prohibit-password
|
|
712
708
|
PubkeyAuthentication yes
|
|
713
709
|
PasswordAuthentication no
|
|
710
|
+
KbdInteractiveAuthentication no
|
|
711
|
+
UsePAM yes
|
|
714
712
|
SSHDEOF
|
|
715
713
|
|
|
714
|
+
if [ "${SSH_PORT}" != "22" ]; then
|
|
715
|
+
semanage port -a -t ssh_port_t -p tcp "${SSH_PORT}" 2>/dev/null || \
|
|
716
|
+
semanage port -m -t ssh_port_t -p tcp "${SSH_PORT}"
|
|
717
|
+
fi
|
|
718
|
+
|
|
716
719
|
# Create the admin login accounts. create_user <name> writes the authorized key,
|
|
717
720
|
# wheel membership and passwordless sudo. Passwords are applied after the chroot.
|
|
718
721
|
create_user() {
|
|
@@ -738,11 +741,24 @@ chmod 600 /root/.ssh/authorized_keys
|
|
|
738
741
|
create_user "\${ADMIN_USER}"
|
|
739
742
|
create_user "\${DEPLOY_USER}"
|
|
740
743
|
|
|
744
|
+
restorecon -RF /etc/ssh /etc/sudoers.d /root/.ssh /home 2>/dev/null
|
|
745
|
+
touch /.autorelabel
|
|
746
|
+
|
|
741
747
|
# Build initramfs for the installed kernel.
|
|
742
748
|
KVER=\\\$(ls /lib/modules | head -1)
|
|
743
749
|
[ -n "\\\$KVER" ] && dracut -f /boot/initramfs-\\\$KVER.img "\\\$KVER"
|
|
744
750
|
CHROOTEOF
|
|
745
751
|
|
|
752
|
+
CHROOT_RC=\$?
|
|
753
|
+
if [ "\$CHROOT_RC" -ne 0 ]; then
|
|
754
|
+
ilog "FATAL: installed-system configuration failed (rc=\$CHROOT_RC)"
|
|
755
|
+
post_status "failed" "\"detail\":\"installed-system configuration rc=\$CHROOT_RC\""
|
|
756
|
+
for d in dev proc sys run; do umount -l "\$TARGET_MNT/\$d" 2>/dev/null; done
|
|
757
|
+
umount -R "\$TARGET_MNT" 2>/dev/null || true
|
|
758
|
+
rm -f "\$INSTALL_LOCK"
|
|
759
|
+
exit 1
|
|
760
|
+
fi
|
|
761
|
+
|
|
746
762
|
# Set console passwords AFTER the chroot heredoc, from decoded installer vars.
|
|
747
763
|
# Primary path: pipe 'user:password' into 'chroot chpasswd' (keeps password
|
|
748
764
|
# characters out of any heredoc). Fallback: hash with openssl and apply via
|
package/scripts/test-monitor.sh
CHANGED
|
@@ -24,7 +24,7 @@ MODE=runtime # runtime | instance
|
|
|
24
24
|
ENV=development # development | production
|
|
25
25
|
DEPLOY_ID=dd-test # deploy id (instance mode: parent of conf.instances.json)
|
|
26
26
|
INSTANCE_IDS= # instance mode: csv of ids (default: all in conf.instances.json)
|
|
27
|
-
IMAGE=underpost/wp:v3.
|
|
27
|
+
IMAGE=underpost/wp:v3.3.0 # runtime mode image (instance mode reads image from conf)
|
|
28
28
|
VERSIONS=green # csv of blue/green versions
|
|
29
29
|
REPLICAS=1 # replicas per deployment
|
|
30
30
|
NAMESPACE=default # k8s namespace
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback-world default items — process-local override store.
|
|
3
|
+
*
|
|
4
|
+
* The procedural fallback world is never persisted, so its default item set
|
|
5
|
+
* has no collection to live in. This module holds the set the FallbackWorldEngine
|
|
6
|
+
* view composed, in memory, for the lifetime of the engine process:
|
|
7
|
+
*
|
|
8
|
+
* - written by POST /api/cyberia-instance/fallback-world/hot-reload
|
|
9
|
+
* - read by fetchFullInstance()'s fallback branch (instance-data.js) and
|
|
10
|
+
* GET /api/cyberia-instance/fallback-world[/default-items]
|
|
11
|
+
*
|
|
12
|
+
* Deliberately NOT persisted: an engine restart drops back to the code defaults,
|
|
13
|
+
* so a stale editor session can never become the permanent shape of the world.
|
|
14
|
+
* This keeps the fallback path's "code defaults are authoritative" invariant —
|
|
15
|
+
* the only thing an operator can layer on top is this explicit, volatile list.
|
|
16
|
+
*
|
|
17
|
+
* @module src/api/cyberia-instance/cyberia-fallback-default-items.js
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** @typedef {{ id: string, defaultPlayerInventory: boolean }} FallbackDefaultItem */
|
|
21
|
+
|
|
22
|
+
/** @type {FallbackDefaultItem[]} */
|
|
23
|
+
let defaultItems = [];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Coerce a caller-supplied list into the canonical `{ id, defaultPlayerInventory }`
|
|
27
|
+
* shape. Accepts the legacy `string[]` form and drops blank/duplicate ids so the
|
|
28
|
+
* world generator never sees a malformed entry.
|
|
29
|
+
*
|
|
30
|
+
* @param {Array<string|FallbackDefaultItem>} entries
|
|
31
|
+
* @returns {FallbackDefaultItem[]}
|
|
32
|
+
*/
|
|
33
|
+
function normalizeFallbackDefaultItems(entries) {
|
|
34
|
+
if (!Array.isArray(entries)) return [];
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
const normalized = [];
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
const raw = typeof entry === 'string' ? { id: entry } : entry;
|
|
39
|
+
const id = typeof raw?.id === 'string' ? raw.id.trim() : '';
|
|
40
|
+
if (!id || seen.has(id)) continue;
|
|
41
|
+
seen.add(id);
|
|
42
|
+
normalized.push({ id, defaultPlayerInventory: !!raw.defaultPlayerInventory });
|
|
43
|
+
}
|
|
44
|
+
return normalized;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Current override set. Returns a copy so callers cannot mutate the store.
|
|
49
|
+
* @returns {FallbackDefaultItem[]}
|
|
50
|
+
*/
|
|
51
|
+
const getFallbackDefaultItems = () => defaultItems.map((entry) => ({ ...entry }));
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Replace the override set. An empty list clears it, restoring pure code defaults.
|
|
55
|
+
* @param {Array<string|FallbackDefaultItem>} entries
|
|
56
|
+
* @returns {FallbackDefaultItem[]} The stored set.
|
|
57
|
+
*/
|
|
58
|
+
function setFallbackDefaultItems(entries) {
|
|
59
|
+
defaultItems = normalizeFallbackDefaultItems(entries);
|
|
60
|
+
return getFallbackDefaultItems();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { getFallbackDefaultItems, setFallbackDefaultItems, normalizeFallbackDefaultItems };
|
|
@@ -179,7 +179,7 @@ function generateFallbackMap(mapCode, colors, opts = {}) {
|
|
|
179
179
|
const portalEntities = generatePortalEntities(mapDims, colors, { grid });
|
|
180
180
|
|
|
181
181
|
// 6. Bots — placed on walkable cells (avoids obstacles, portals, NPCs)
|
|
182
|
-
const bots = generateBots(mapDims, colors, { count: opts.botCount, grid });
|
|
182
|
+
const bots = mapCode === 'fallback-map-0' ? [] : generateBots(mapDims, colors, { count: opts.botCount, grid });
|
|
183
183
|
|
|
184
184
|
// 7. Resources — static exploitable entities placed on walkable cells
|
|
185
185
|
const resources = generateResources(mapDims, colors, { count: opts.resourceCount, grid });
|
|
@@ -232,6 +232,11 @@ function generateFallbackMap(mapCode, colors, opts = {}) {
|
|
|
232
232
|
* @param {number} [opts.resourceCount] Resources per map (random if omitted).
|
|
233
233
|
* @param {number} [opts.staticCount] Static decorators per map (random if omitted).
|
|
234
234
|
* @param {Array} [opts.colors] Override palette.
|
|
235
|
+
* @param {Array<{id: string, defaultPlayerInventory: boolean}>} [opts.itemIds=[]]
|
|
236
|
+
* Instance-level default items, mirroring `CyberiaInstance.itemIds`. Entries
|
|
237
|
+
* flagged `defaultPlayerInventory` are merged into the player entity default
|
|
238
|
+
* by `applyInstanceDefaultPlayerInventory`; every id is also resolved to an
|
|
239
|
+
* atlas at boot. Layout is unaffected, so this stays outside the world seed.
|
|
235
240
|
* @returns {{
|
|
236
241
|
* instance: object,
|
|
237
242
|
* maps: object[],
|
|
@@ -256,6 +261,7 @@ function generateFallbackWorld(opts = {}) {
|
|
|
256
261
|
// fallback before atlases load. The C client resolves real colours
|
|
257
262
|
// through domain/presentation_runtime — it does not read this value.
|
|
258
263
|
colors = PALETTE,
|
|
264
|
+
itemIds = [],
|
|
259
265
|
} = opts;
|
|
260
266
|
|
|
261
267
|
// Surface item-id drift loudly on the very first build, so a missing
|
|
@@ -314,6 +320,7 @@ function generateFallbackWorld(opts = {}) {
|
|
|
314
320
|
portals,
|
|
315
321
|
topologyMode: 'procedural',
|
|
316
322
|
playerSpawn: { ...DEFAULT_PLAYER_SPAWN },
|
|
323
|
+
itemIds: itemIds.map((entry) => ({ ...entry })),
|
|
317
324
|
};
|
|
318
325
|
|
|
319
326
|
return {
|
|
@@ -30,6 +30,9 @@ const CyberiaInstanceController = buildCrudController(CyberiaInstanceService, {
|
|
|
30
30
|
portalConnect: serviceHandler(CyberiaInstanceService.portalConnect),
|
|
31
31
|
// Moderator/admin-triggered world reload on a running cyberia-server.
|
|
32
32
|
hotReload: serviceHandler(CyberiaInstanceService.hotReload, { errorStatus: 502 }),
|
|
33
|
+
// Fallback-world default items (volatile) + its own reload trigger.
|
|
34
|
+
fallbackDefaultItems: serviceHandler(CyberiaInstanceService.fallbackDefaultItems),
|
|
35
|
+
fallbackHotReload: serviceHandler(CyberiaInstanceService.fallbackHotReload, { errorStatus: 502 }),
|
|
33
36
|
// Boot transport (REST fallback of the gRPC CyberiaDataService).
|
|
34
37
|
bootPing: serviceHandler(CyberiaInstanceBootService.ping),
|
|
35
38
|
bootObjectLayerBatch: serviceHandler(CyberiaInstanceBootService.objectLayerBatch, { errorStatus: 500 }),
|
|
@@ -38,6 +38,19 @@ class CyberiaInstanceRouter {
|
|
|
38
38
|
async (req, res) => await CyberiaInstanceController.bootFullInstance(req, res, options),
|
|
39
39
|
);
|
|
40
40
|
router.get(`/fallback-world`, async (req, res) => await CyberiaInstanceController.fallbackWorld(req, res, options));
|
|
41
|
+
// Fallback-world default items — volatile, process-local (never persisted).
|
|
42
|
+
// The read is open (same as /fallback-world); staging them and triggering a
|
|
43
|
+
// rebuild is elevated privilege, like every other hot-reload path.
|
|
44
|
+
router.get(
|
|
45
|
+
`/fallback-world/default-items`,
|
|
46
|
+
async (req, res) => await CyberiaInstanceController.fallbackDefaultItems(req, res, options),
|
|
47
|
+
);
|
|
48
|
+
router.post(
|
|
49
|
+
`/fallback-world/hot-reload`,
|
|
50
|
+
options.authMiddleware,
|
|
51
|
+
moderatorGuard,
|
|
52
|
+
async (req, res) => await CyberiaInstanceController.fallbackHotReload(req, res, options),
|
|
53
|
+
);
|
|
41
54
|
// Instance Map — static topology/presence plus dynamic player capability activity.
|
|
42
55
|
router.get(
|
|
43
56
|
`/instance-map/:instanceCode/static`,
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
fallbackListInstance,
|
|
8
8
|
DEFAULT_FALLBACK_INSTANCE_CODE,
|
|
9
9
|
} from './cyberia-fallback-world.js';
|
|
10
|
+
import { getFallbackDefaultItems, setFallbackDefaultItems } from './cyberia-fallback-default-items.js';
|
|
11
|
+
import { CYBERIA_INSTANCE_CONF_DEFAULTS } from '../cyberia-server-defaults/cyberia-server-defaults.js';
|
|
10
12
|
import { triggerHotReload } from '../../projects/cyberia/hot-reload-trigger.js';
|
|
11
13
|
|
|
12
14
|
const logger = loggerFactory(import.meta);
|
|
@@ -183,8 +185,49 @@ class CyberiaInstanceService {
|
|
|
183
185
|
botCount: q.botCount ? parseInt(q.botCount, 10) : undefined,
|
|
184
186
|
obstacleCount: q.obstacleCount ? parseInt(q.obstacleCount, 10) : undefined,
|
|
185
187
|
foregroundCount: q.foregroundCount ? parseInt(q.foregroundCount, 10) : undefined,
|
|
188
|
+
itemIds: getFallbackDefaultItems(),
|
|
186
189
|
});
|
|
187
190
|
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Current fallback-world default items — the volatile set the
|
|
194
|
+
* FallbackWorldEngine view last pushed, or `[]` when the engine is running on
|
|
195
|
+
* pure code defaults. Lets the view reopen showing what this process serves.
|
|
196
|
+
*
|
|
197
|
+
* `entityDefaultItemIds` are the ids the code defaults already ship in an
|
|
198
|
+
* entity's `defaultObjectLayers`. Selecting one of them and leaving
|
|
199
|
+
* `defaultPlayerInventory` unchecked REMOVES it (see
|
|
200
|
+
* applyInstanceDefaultPlayerInventory), so the editor needs to be able to warn
|
|
201
|
+
* before an operator silently strips the player's starting skin or weapon.
|
|
202
|
+
*/
|
|
203
|
+
static fallbackDefaultItems = async () => {
|
|
204
|
+
const entityDefaultItemIds = new Set();
|
|
205
|
+
for (const entityDefault of CYBERIA_INSTANCE_CONF_DEFAULTS.entityDefaults || []) {
|
|
206
|
+
for (const layer of entityDefault.defaultObjectLayers || []) {
|
|
207
|
+
if (layer.itemId) entityDefaultItemIds.add(layer.itemId);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return { itemIds: getFallbackDefaultItems(), entityDefaultItemIds: [...entityDefaultItemIds].sort() };
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Stage the fallback world's default items, then ask a running cyberia-server
|
|
215
|
+
* to rebuild. The items are not persisted (see cyberia-fallback-default-items):
|
|
216
|
+
* they are staged here first so the rebuild's `getFullInstance` re-fetch picks
|
|
217
|
+
* them up, which is what makes them reach the server at all.
|
|
218
|
+
*
|
|
219
|
+
* `instanceCode` is intentionally left empty — the target world is addressed by
|
|
220
|
+
* `serverUrl` (origin, or origin + variant sub-path), and naming the synthetic
|
|
221
|
+
* `fallback` code would be rejected by any server serving a real instance code.
|
|
222
|
+
*/
|
|
223
|
+
static fallbackHotReload = async (req) => {
|
|
224
|
+
const { serverUrl, mode, itemIds } = req.body || {};
|
|
225
|
+
if (!serverUrl) throw new Error('serverUrl is required');
|
|
226
|
+
|
|
227
|
+
const staged = setFallbackDefaultItems(itemIds || []);
|
|
228
|
+
const { transport, result, grpcError } = await triggerHotReload({ serverUrl, instanceCode: '', mode });
|
|
229
|
+
return { transport, itemIds: staged, grpcError, ...result };
|
|
230
|
+
};
|
|
188
231
|
}
|
|
189
232
|
|
|
190
233
|
export { CyberiaInstanceService };
|
|
@@ -148,6 +148,7 @@ const CyberiaInstanceConfSchema = new Schema(
|
|
|
148
148
|
// ── Player defaults ──────────────────────────────────────────────
|
|
149
149
|
defaultPlayerWidth: { type: Number, default: D.defaultPlayerWidth },
|
|
150
150
|
defaultPlayerHeight: { type: Number, default: D.defaultPlayerHeight },
|
|
151
|
+
playerBaseSpeed: { type: Number, default: D.playerBaseSpeed },
|
|
151
152
|
playerBaseLifeRegenMin: { type: Number, default: D.playerBaseLifeRegenMin },
|
|
152
153
|
playerBaseLifeRegenMax: { type: Number, default: D.playerBaseLifeRegenMax },
|
|
153
154
|
sumStatsLimit: { type: Number, default: D.sumStatsLimit },
|