feat(zhulan): add restricted remote development cell
This commit is contained in:
parent
5f9e83e1b7
commit
366b8911e4
22 changed files with 4503 additions and 0 deletions
191
server-tools/zhulan-remote-cell/deploy/install-runtime.sh
Executable file
191
server-tools/zhulan-remote-cell/deploy/install-runtime.sh
Executable file
|
|
@ -0,0 +1,191 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
echo "INSTALL_REQUIRES_ROOT" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SOURCE_DIR="${1:-}"
|
||||
if [[ -z "$SOURCE_DIR" || ! -f "$SOURCE_DIR/runtime/zhulan_cell.py" ]]; then
|
||||
echo "SOURCE_DIR_INVALID" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
EXPECTED_HOST="${ZHULAN_EXPECTED_HOST:-VM-12-12-ubuntu}"
|
||||
EXPECTED_DMI="${ZHULAN_EXPECTED_DMI:-7a500f2d-9aed-4b93-b3b8-59c87c65d031}"
|
||||
ACTUAL_HOST="$(hostname)"
|
||||
ACTUAL_DMI="$(tr '[:upper:]' '[:lower:]' </sys/class/dmi/id/product_uuid)"
|
||||
if [[ "$ACTUAL_HOST" != "$EXPECTED_HOST" || "$ACTUAL_DMI" != "$EXPECTED_DMI" ]]; then
|
||||
echo "TARGET_IDENTITY_MISMATCH host=$ACTUAL_HOST dmi=$ACTUAL_DMI" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v bwrap >/dev/null 2>&1 || ! command -v apparmor_parser >/dev/null 2>&1; then
|
||||
apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends apparmor bubblewrap
|
||||
fi
|
||||
|
||||
INSTALL_ROOT="/opt/guanghu/zhulan-remote-cell"
|
||||
STATE_ROOT="/var/lib/guanghu/zhulan-remote-cell"
|
||||
WORKSPACE_ROOT="/srv/guanghu/zhulan-cell/workspaces"
|
||||
CANDIDATE_ROOT="/srv/guanghu/zhulan-cell/candidates"
|
||||
SECRET_ROOT="/etc/guanghu/secrets"
|
||||
ENV_FILE="/etc/guanghu/zhulan-remote-cell.env"
|
||||
SERVICE_FILE="/etc/systemd/system/zhulan-remote-cell.service"
|
||||
EXECUTOR_SERVICE_FILE="/etc/systemd/system/zhulan-validation-executor.service"
|
||||
APPARMOR_FILE="/etc/apparmor.d/zhulan-remote-cell-bwrap"
|
||||
BACKUP_ROOT="/var/backups/guanghu/zhulan-remote-cell"
|
||||
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
|
||||
|
||||
getent passwd zhulan-runtime >/dev/null || {
|
||||
echo "RUNTIME_USER_MUST_BE_PRECREATED" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
install -d -o root -g root -m 0755 "$INSTALL_ROOT" "$BACKUP_ROOT"
|
||||
install -d -o zhulan-runtime -g zhulan-runtime -m 0700 "$STATE_ROOT"
|
||||
install -d -o zhulan-runtime -g zhulan-runtime -m 0700 "$WORKSPACE_ROOT"
|
||||
install -d -o zhulan-runtime -g zhulan-runtime -m 0700 "$CANDIDATE_ROOT"
|
||||
install -d -o root -g zhulan-runtime -m 0750 "$SECRET_ROOT"
|
||||
|
||||
if [[ -d "$INSTALL_ROOT/runtime" ]]; then
|
||||
tar -C "$INSTALL_ROOT" -czf "$BACKUP_ROOT/runtime-$STAMP.tgz" runtime ui policy.json 2>/dev/null || true
|
||||
fi
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
install -m 0600 "$ENV_FILE" "$BACKUP_ROOT/env-$STAMP"
|
||||
fi
|
||||
if [[ -f "$SERVICE_FILE" ]]; then
|
||||
install -m 0644 "$SERVICE_FILE" "$BACKUP_ROOT/service-$STAMP"
|
||||
fi
|
||||
if [[ -f "$EXECUTOR_SERVICE_FILE" ]]; then
|
||||
install -m 0644 "$EXECUTOR_SERVICE_FILE" "$BACKUP_ROOT/executor-service-$STAMP"
|
||||
fi
|
||||
if [[ -f "$APPARMOR_FILE" ]]; then
|
||||
install -m 0644 "$APPARMOR_FILE" "$BACKUP_ROOT/apparmor-$STAMP"
|
||||
fi
|
||||
|
||||
install -d -o root -g root -m 0755 "$INSTALL_ROOT/runtime" "$INSTALL_ROOT/ui" "$INSTALL_ROOT/contracts"
|
||||
install -o root -g root -m 0755 "$SOURCE_DIR/runtime/zhulan_cell.py" "$INSTALL_ROOT/runtime/zhulan_cell.py"
|
||||
install -o root -g root -m 0755 "$SOURCE_DIR/runtime/zhulan_code_gate.py" "$INSTALL_ROOT/runtime/zhulan_code_gate.py"
|
||||
install -o root -g root -m 0755 "$SOURCE_DIR/runtime/zhulan_validation_executor.py" "$INSTALL_ROOT/runtime/zhulan_validation_executor.py"
|
||||
# Keep the distro bwrap binary non-setuid. A dedicated group-executable copy
|
||||
# lets AppArmor grant userns only to this runtime path instead of weakening the
|
||||
# host-wide unprivileged-userns policy or opening /usr/bin/bwrap for all users.
|
||||
install -o root -g zhulan-runtime -m 0750 /usr/bin/bwrap "$INSTALL_ROOT/runtime/zhulan-bwrap"
|
||||
install -o root -g root -m 0644 "$SOURCE_DIR/ui/index.html" "$INSTALL_ROOT/ui/index.html"
|
||||
install -o root -g root -m 0644 "$SOURCE_DIR/ui/styles.css" "$INSTALL_ROOT/ui/styles.css"
|
||||
install -o root -g root -m 0644 "$SOURCE_DIR/ui/app.js" "$INSTALL_ROOT/ui/app.js"
|
||||
install -o root -g root -m 0644 "$SOURCE_DIR/policy.example.json" "$INSTALL_ROOT/policy.json"
|
||||
install -o root -g root -m 0644 "$SOURCE_DIR/README.md" "$INSTALL_ROOT/README.md"
|
||||
|
||||
if [[ -d "$SOURCE_DIR/contracts" ]]; then
|
||||
find "$SOURCE_DIR/contracts" -maxdepth 1 -type f -print0 | while IFS= read -r -d '' file; do
|
||||
install -o root -g root -m 0444 "$file" "$INSTALL_ROOT/contracts/$(basename "$file")"
|
||||
done
|
||||
fi
|
||||
|
||||
# Install current Fifth Domain brains and Zhulan entry as read-only runtime
|
||||
# contracts from the same exact repository checkout as this installer.
|
||||
REPO_ROOT="$(cd "$SOURCE_DIR/../.." && pwd)"
|
||||
SOURCE_COMMIT="${ZHULAN_SOURCE_COMMIT:-}"
|
||||
if [[ -z "$SOURCE_COMMIT" ]] && git -C "$REPO_ROOT" rev-parse HEAD >/dev/null 2>&1; then
|
||||
SOURCE_COMMIT="$(git -C "$REPO_ROOT" rev-parse HEAD)"
|
||||
fi
|
||||
if [[ ! "$SOURCE_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
echo "SOURCE_COMMIT_REQUIRED" >&2
|
||||
exit 1
|
||||
fi
|
||||
for relative in \
|
||||
"skills/shared/guanghu-ui-brain/SKILL.md" \
|
||||
"skills/shared/guanghu-ui-brain/BRAIN.hdlp" \
|
||||
"skills/shared/guanghu-client-ui-brain/SKILL.md" \
|
||||
"skills/shared/guanghu-client-ui-brain/BRAIN.hdlp" \
|
||||
"光之湖/ICE-GL-ZL-001-铸澜/WAKE.hdlp" \
|
||||
"光之湖/ICE-GL-ZL-001-铸澜/INDEX.hdlp" \
|
||||
"光之湖/ICE-GL-ZL-001-铸澜/CURRENT.hdlp" \
|
||||
"光之湖/ICE-GL-ZL-001-铸澜/PERMANENT-MEMORY-WRITE-PROTOCOL.hdlp"; do
|
||||
source_file="$REPO_ROOT/$relative"
|
||||
if [[ ! -f "$source_file" ]]; then
|
||||
echo "CONTRACT_SOURCE_MISSING $relative" >&2
|
||||
exit 1
|
||||
fi
|
||||
safe_name="$(printf '%s' "$relative" | tr '/ ' '__')"
|
||||
install -o root -g root -m 0444 "$source_file" "$INSTALL_ROOT/contracts/$safe_name"
|
||||
done
|
||||
|
||||
printf '%s\n' "$SOURCE_COMMIT" >"$INSTALL_ROOT/contracts/REPOSITORY-SOURCE-SHA"
|
||||
chmod 0444 "$INSTALL_ROOT/contracts/REPOSITORY-SOURCE-SHA"
|
||||
|
||||
SECRET_FILE="$SECRET_ROOT/zhulan-remote-cell.secret"
|
||||
if [[ ! -f "$SECRET_FILE" ]]; then
|
||||
umask 0177
|
||||
openssl rand -hex 48 >"$SECRET_FILE"
|
||||
fi
|
||||
chown root:zhulan-runtime "$SECRET_FILE"
|
||||
chmod 0640 "$SECRET_FILE"
|
||||
|
||||
install -o root -g zhulan-runtime -m 0640 "$SOURCE_DIR/deploy/zhulan-remote-cell.env.example" "$ENV_FILE"
|
||||
install -o root -g root -m 0644 "$SOURCE_DIR/deploy/zhulan-remote-cell.service" "$SERVICE_FILE"
|
||||
install -o root -g root -m 0644 "$SOURCE_DIR/deploy/zhulan-validation-executor.service" "$EXECUTOR_SERVICE_FILE"
|
||||
install -o root -g root -m 0644 "$SOURCE_DIR/deploy/zhulan-bwrap.apparmor" "$APPARMOR_FILE"
|
||||
apparmor_parser -r "$APPARMOR_FILE"
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable zhulan-validation-executor.service
|
||||
systemctl restart zhulan-validation-executor.service
|
||||
for _ in $(seq 1 30); do
|
||||
if [[ -S /run/guanghu/zhulan-validation/executor.sock ]]; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [[ ! -S /run/guanghu/zhulan-validation/executor.sock ]]; then
|
||||
systemctl status zhulan-validation-executor.service --no-pager >&2 || true
|
||||
echo "VALIDATION_EXECUTOR_HEALTH_FAILED" >&2
|
||||
exit 1
|
||||
fi
|
||||
systemctl enable zhulan-remote-cell.service
|
||||
systemctl restart zhulan-remote-cell.service
|
||||
|
||||
for _ in $(seq 1 30); do
|
||||
if curl --fail --silent --show-error --max-time 2 http://127.0.0.1:17631/health >"$STATE_ROOT/health.json.tmp"; then
|
||||
mv "$STATE_ROOT/health.json.tmp" "$STATE_ROOT/health.json"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [[ ! -s "$STATE_ROOT/health.json" ]]; then
|
||||
systemctl status zhulan-remote-cell.service --no-pager >&2 || true
|
||||
echo "RUNTIME_HEALTH_FAILED" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SOURCE_SHA256="$(find \
|
||||
"$INSTALL_ROOT/runtime" \
|
||||
"$INSTALL_ROOT/ui" \
|
||||
"$INSTALL_ROOT/contracts" \
|
||||
"$INSTALL_ROOT/policy.json" \
|
||||
"$INSTALL_ROOT/README.md" \
|
||||
-type f -print0 | sort -z | xargs -0 sha256sum | sha256sum | awk '{print $1}')"
|
||||
cat >"$STATE_ROOT/install-receipt.json.tmp" <<EOF
|
||||
{
|
||||
"schema": "guanghu.zhulan-runtime-install-receipt/v1",
|
||||
"development_id": "DEV-20260813-005",
|
||||
"runtime_node": "BS-SG-003",
|
||||
"front_node_role": "BS-GZ-006_PROXY_ONLY",
|
||||
"installed_at": "$STAMP",
|
||||
"source_tree_hash": "$SOURCE_SHA256",
|
||||
"source_commit": "$SOURCE_COMMIT",
|
||||
"service": "zhulan-remote-cell.service",
|
||||
"validation_executor": "zhulan-validation-executor.service",
|
||||
"listener": "127.0.0.1:17631",
|
||||
"health": "PASS"
|
||||
}
|
||||
EOF
|
||||
chown zhulan-runtime:zhulan-runtime "$STATE_ROOT/install-receipt.json.tmp"
|
||||
chmod 0600 "$STATE_ROOT/install-receipt.json.tmp"
|
||||
mv "$STATE_ROOT/install-receipt.json.tmp" "$STATE_ROOT/install-receipt.json"
|
||||
|
||||
cat "$STATE_ROOT/install-receipt.json"
|
||||
Loading…
Reference in a new issue