guanghu-ice-heart/server-tools/zhulan-remote-cell/deploy/install-codex-remote-ssh.sh

154 lines
5.7 KiB
Shell

#!/usr/bin/env bash
set -euo pipefail
if [[ "$(id -u)" -ne 0 ]]; then
echo "INSTALL_REQUIRES_ROOT" >&2
exit 1
fi
SOURCE_DIR="${1:-}"
AUTHORIZED_KEY_FILE="${2:-}"
if [[ -z "$SOURCE_DIR" || ! -f "$SOURCE_DIR/remote/zhulan_guard.py" ]]; then
echo "SOURCE_DIR_INVALID" >&2
exit 1
fi
if [[ -z "$AUTHORIZED_KEY_FILE" || ! -s "$AUTHORIZED_KEY_FILE" ]]; then
echo "AUTHORIZED_KEY_REQUIRED" >&2
exit 1
fi
if grep -qvE '^ssh-ed25519 [A-Za-z0-9+/=]+( .*)?$' "$AUTHORIZED_KEY_FILE"; then
echo "AUTHORIZED_KEY_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" >&2
exit 1
fi
REMOTE_USER="zhulan-codex"
REMOTE_HOME="/srv/guanghu/zhulan-codex/home"
REMOTE_ROOT="/srv/guanghu/zhulan-codex"
WORKSPACE_ROOT="$REMOTE_ROOT/workspaces"
CANDIDATE_ROOT="$REMOTE_ROOT/candidates"
POLICY_ROOT="/etc/guanghu/zhulan-codex"
HOOK_ROOT="$POLICY_ROOT/hooks"
REQUIREMENTS_ROOT="/etc/codex"
SSHD_DROPIN="/etc/ssh/sshd_config.d/60-zhulan-codex.conf"
REPOSITORY_URL="https://guanghulab.com/code/bingshuo/guanghu-ice-heart.git"
REPOSITORY_DIR="$WORKSPACE_ROOT/guanghu-ice-heart"
CODEX_VERSION="${ZHULAN_CODEX_VERSION:-0.147.0}"
SOURCE_COMMIT="${ZHULAN_SOURCE_COMMIT:-}"
if [[ ! "$SOURCE_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
echo "SOURCE_COMMIT_REQUIRED" >&2
exit 1
fi
getent passwd "$REMOTE_USER" >/dev/null || useradd \
--home-dir "$REMOTE_HOME" \
--create-home \
--shell /bin/bash \
--comment "Zhulan Codex Remote restricted developer" \
"$REMOTE_USER"
passwd -l "$REMOTE_USER" >/dev/null
gpasswd -d "$REMOTE_USER" sudo >/dev/null 2>&1 || true
gpasswd -d "$REMOTE_USER" adm >/dev/null 2>&1 || true
install -d -o root -g root -m 0755 "$REMOTE_ROOT"
install -d -o "$REMOTE_USER" -g "$REMOTE_USER" -m 0700 "$REMOTE_HOME" "$WORKSPACE_ROOT" "$CANDIDATE_ROOT"
install -d -o "$REMOTE_USER" -g "$REMOTE_USER" -m 0700 "$REMOTE_HOME/.ssh"
install -d -o "$REMOTE_USER" -g "$REMOTE_USER" -m 0700 "$REMOTE_HOME/.codex"
{
printf 'restrict,pty '
cat "$AUTHORIZED_KEY_FILE"
} >"$REMOTE_HOME/.ssh/authorized_keys.tmp"
chown "$REMOTE_USER:$REMOTE_USER" "$REMOTE_HOME/.ssh/authorized_keys.tmp"
chmod 0600 "$REMOTE_HOME/.ssh/authorized_keys.tmp"
mv "$REMOTE_HOME/.ssh/authorized_keys.tmp" "$REMOTE_HOME/.ssh/authorized_keys"
install -d -o root -g root -m 0755 "$POLICY_ROOT" "$HOOK_ROOT" "$REQUIREMENTS_ROOT"
install -o root -g root -m 0444 "$SOURCE_DIR/remote/LANE.hdlp" "$POLICY_ROOT/LANE.hdlp"
install -o root -g root -m 0555 "$SOURCE_DIR/remote/zhulan_guard.py" "$HOOK_ROOT/zhulan_guard.py"
install -o root -g root -m 0444 "$SOURCE_DIR/remote/requirements.toml" "$REQUIREMENTS_ROOT/requirements.toml"
cat >"$SSHD_DROPIN.tmp" <<'EOF'
Match User zhulan-codex
AuthenticationMethods publickey
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
PermitTTY yes
PermitUserEnvironment no
EOF
chmod 0644 "$SSHD_DROPIN.tmp"
mv "$SSHD_DROPIN.tmp" "$SSHD_DROPIN"
/usr/sbin/sshd -t
systemctl reload ssh
if ! command -v codex >/dev/null 2>&1 || [[ "$(codex --version 2>/dev/null)" != *"$CODEX_VERSION"* ]]; then
npm install --global "@openai/codex@$CODEX_VERSION"
fi
if [[ ! -d "$REPOSITORY_DIR/.git" ]]; then
runuser -u "$REMOTE_USER" -- git clone "$REPOSITORY_URL" "$REPOSITORY_DIR"
fi
runuser -u "$REMOTE_USER" -- git -C "$REPOSITORY_DIR" fetch --prune origin main
runuser -u "$REMOTE_USER" -- git -C "$REPOSITORY_DIR" remote set-url --push origin DISABLED_CENTRAL_PUSH
if [[ ! -d "$CANDIDATE_ROOT/guanghu-ice-heart.git" ]]; then
runuser -u "$REMOTE_USER" -- git init --bare "$CANDIDATE_ROOT/guanghu-ice-heart.git"
fi
if runuser -u "$REMOTE_USER" -- git -C "$REPOSITORY_DIR" remote get-url candidate >/dev/null 2>&1; then
runuser -u "$REMOTE_USER" -- git -C "$REPOSITORY_DIR" remote set-url candidate "$CANDIDATE_ROOT/guanghu-ice-heart.git"
else
runuser -u "$REMOTE_USER" -- git -C "$REPOSITORY_DIR" remote add candidate "$CANDIDATE_ROOT/guanghu-ice-heart.git"
fi
install -o "$REMOTE_USER" -g "$REMOTE_USER" -m 0644 "$SOURCE_DIR/remote/AGENTS.md" "$REMOTE_HOME/.codex/AGENTS.md"
install -d -o "$REMOTE_USER" -g "$REMOTE_USER" -m 0700 "$REPOSITORY_DIR/.zhulan/continuity"
if ! grep -qxF '/.zhulan/' "$REPOSITORY_DIR/.git/info/exclude"; then
printf '%s\n' '/.zhulan/' >>"$REPOSITORY_DIR/.git/info/exclude"
fi
chown "$REMOTE_USER:$REMOTE_USER" "$REPOSITORY_DIR/.git/info/exclude"
runuser -u "$REMOTE_USER" -- git -C "$REPOSITORY_DIR" config user.name "Zhulan Remote Candidate"
runuser -u "$REMOTE_USER" -- git -C "$REPOSITORY_DIR" config user.email "zhulan-remote@localhost"
if id -nG "$REMOTE_USER" | tr ' ' '\n' | grep -qx sudo; then
echo "REMOTE_USER_HAS_SUDO" >&2
exit 1
fi
if sudo -n -u "$REMOTE_USER" sudo -n true >/dev/null 2>&1; then
echo "REMOTE_USER_CAN_SUDO" >&2
exit 1
fi
RECEIPT="$REMOTE_ROOT/install-receipt.json"
cat >"$RECEIPT.tmp" <<EOF
{
"schema": "guanghu.zhulan-codex-remote-ssh-install/v1",
"development_id": "DEV-20260813-005",
"persona_id": "ICE-GL-ZL-001",
"runtime_node": "BS-SG-003",
"front_node_role": "BS-GZ-006_PROXY_ONLY",
"source_commit": "$SOURCE_COMMIT",
"codex_version": "$CODEX_VERSION",
"remote_user": "$REMOTE_USER",
"workspace": "$REPOSITORY_DIR",
"sudo": false,
"central_push_credentials": false,
"managed_hooks": true,
"candidate_remote_only": true,
"health": "PASS"
}
EOF
chown root:root "$RECEIPT.tmp"
chmod 0444 "$RECEIPT.tmp"
mv "$RECEIPT.tmp" "$RECEIPT"
cat "$RECEIPT"