Six fixes addressing operational correctness on a real Debian host:
1. Ownership after git operations: chown -R zopu:zopu on the checkout
after clone/update/rollback before running bun install/build as the
service user. .env kept at 0600 with explicit chmod after each
operation.
2. sudo replaced with runuser: minimal Debian does not include sudo.
runuser is part of util-linux (essential) and always available.
All three scripts (bootstrap, update, rollback) now use runuser -u.
3. cron.d entry fixed: /etc/cron.d format requires a username field.
Added ${SERVICE_USER} between the time fields and the command path.
4. Firewall: added explicit `ufw allow in on tailscale0` rule so the
deny-incoming default does not block Tailscale private-overlay
reachability. Removed inaccurate claim that direct private IP works
by default; documented that an explicit per-interface rule is needed.
5. SupplementaryGroups=docker added to zopu-agent.service: the Orb
sandbox runtime lives in the agent process, not just the daemon.
6. zopu-health.service: added Environment=ENV_FILE=__INSTALL_DIR__/.env
so health-check.sh sources the correct .env at custom install paths.
Verified Flue build output: bun run build:agents produces
packages/agents/dist/server.mjs (confirmed by running the build).
Agent unit ExecStart path is correct.
Validated: bash -n on all 6 shell scripts; mocked health-check smoke
against live RivetKit engine on port 6420; systemd unit structural
checks. No JS/TS/agent files changed.
109 lines
3.1 KiB
Bash
Executable File
109 lines
3.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# update.sh — Update the Zopu runtime to a specific branch or commit.
|
|
#
|
|
# Usage:
|
|
# update.sh # update to latest dogfood/v0
|
|
# update.sh dogfood/v0 # update to latest of branch dogfood/v0
|
|
# update.sh <commit-sha> # checkout and build a specific commit
|
|
#
|
|
# The argument is treated as a branch name first; if no matching remote
|
|
# tracking branch exists it is treated as a commit SHA.
|
|
#
|
|
# .env is gitignored and is never touched by git operations. It survives
|
|
# updates and rollbacks unchanged.
|
|
#
|
|
# Must be run as root (uses runuser to build as the service user).
|
|
|
|
set -euo pipefail
|
|
|
|
INSTALL_DIR="${ZOPU_INSTALL_DIR:-/opt/zopu}"
|
|
SERVICE_USER="${ZOPU_SERVICE_USER:-zopu}"
|
|
TARGET="${1:-dogfood/v0}"
|
|
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
RED='\033[0;31m'
|
|
NC='\033[0m'
|
|
|
|
log() { echo -e "${GREEN}[update]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[update]${NC} $*"; }
|
|
err() { echo -e "${RED}[update]${NC} $*" >&2; }
|
|
|
|
run_as_service() {
|
|
runuser -u "$SERVICE_USER" -- "$@"
|
|
}
|
|
|
|
cd "$INSTALL_DIR"
|
|
|
|
# Record current commit for rollback
|
|
CURRENT_SHA=$(git rev-parse HEAD)
|
|
log "Current HEAD: ${CURRENT_SHA:0:12}"
|
|
echo "$CURRENT_SHA" > "${INSTALL_DIR}/.last-deployed-sha"
|
|
|
|
# Fetch all remotes
|
|
log "Fetching from origin..."
|
|
git fetch origin
|
|
|
|
# Resolve target: branch first, then commit
|
|
if git show-ref --verify --quiet "refs/remotes/origin/${TARGET}"; then
|
|
log "Target is a branch: ${TARGET}"
|
|
git checkout -B "$TARGET" "origin/${TARGET}"
|
|
elif git rev-parse --verify "${TARGET}^{commit}" &>/dev/null; then
|
|
log "Target is a commit: ${TARGET:0:12}"
|
|
git checkout "$TARGET"
|
|
else
|
|
err "'${TARGET}' is not a known branch or valid commit."
|
|
err "Available branches: $(git branch -r | tr '\n' ' ')"
|
|
exit 1
|
|
fi
|
|
|
|
NEW_SHA=$(git rev-parse HEAD)
|
|
log "Now at: ${NEW_SHA:0:12}"
|
|
|
|
# Restore ownership of the checkout to the service user after git operations
|
|
log "Setting ownership of checkout to $SERVICE_USER..."
|
|
chown -R "$SERVICE_USER":"$SERVICE_USER" "$INSTALL_DIR"
|
|
|
|
# Confirm .env is intact and has correct permissions
|
|
if [[ -f "${INSTALL_DIR}/.env" ]]; then
|
|
log ".env preserved."
|
|
chmod 600 "${INSTALL_DIR}/.env"
|
|
else
|
|
err ".env is missing! Restore it from backup before starting services."
|
|
fi
|
|
|
|
# Install and build
|
|
log "Running bun install..."
|
|
run_as_service bun install
|
|
|
|
log "Building daemon binary..."
|
|
run_as_service bun run build:daemon
|
|
|
|
log "Building agent service..."
|
|
run_as_service bun run build:agents
|
|
|
|
# Graceful restart: daemon first (owns RivetKit engine), then agent
|
|
log "Restarting services..."
|
|
systemctl restart zopu-daemon
|
|
sleep 3
|
|
systemctl restart zopu-agent
|
|
sleep 5
|
|
|
|
# Health check
|
|
HEALTH_SCRIPT="${INSTALL_DIR}/deploy/zopu-runtime/scripts/health-check.sh"
|
|
if [[ -x "$HEALTH_SCRIPT" ]]; then
|
|
log "Running health check..."
|
|
if "$HEALTH_SCRIPT"; then
|
|
log "Update complete and healthy."
|
|
else
|
|
err "Health check failed after update!"
|
|
err " journalctl -u zopu-daemon -n 50"
|
|
err " journalctl -u zopu-agent -n 50"
|
|
err "To rollback: ${INSTALL_DIR}/deploy/zopu-runtime/scripts/rollback.sh"
|
|
exit 1
|
|
fi
|
|
else
|
|
log "Update complete. Verify manually."
|
|
fi
|