源码快照 @ 2026-09-02 (source-only, 剔除非源码素材)
This commit is contained in:
Executable
+179
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# test-server-on-daytona.sh — one-command Daytona Den server sandbox.
|
||||
#
|
||||
# Usage:
|
||||
# bash .devcontainer/test-server-on-daytona.sh [branch-or-commit]
|
||||
# bash .devcontainer/test-server-on-daytona.sh [branch-or-commit] --force-install
|
||||
# bash .devcontainer/test-server-on-daytona.sh [branch-or-commit] --seed
|
||||
#
|
||||
# Creates a Daytona sandbox, starts MySQL + Den API + Den Web,
|
||||
# waits for health checks, and prints public preview URLs.
|
||||
|
||||
REF=""
|
||||
FORCE_INSTALL=0
|
||||
RUN_SEED=0
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
# Pid + random suffix so parallel invocations (multiple features/worktrees)
|
||||
# never collide on the second-granularity timestamp.
|
||||
SANDBOX="openwork-server-$(date +%Y%m%d-%H%M%S)-$$-$(od -An -N2 -tx2 /dev/urandom | tr -d ' ')"
|
||||
DAYTONA_SERVER_SNAPSHOT="${DAYTONA_SERVER_SNAPSHOT:-openwork-server}"
|
||||
DAYTONA_TARGET="${DAYTONA_TARGET:-us}"
|
||||
DEN_API_PORT="${DEN_API_PORT:-8788}"
|
||||
DEN_WEB_PORT="${DEN_WEB_PORT:-3005}"
|
||||
MAX_WAIT="${DAYTONA_SERVER_MAX_WAIT:-240}"
|
||||
DEN_GENERATED_ARTIFACT_VIEWS_ENABLED="${DEN_GENERATED_ARTIFACT_VIEWS_ENABLED:-}"
|
||||
if [ -z "$DEN_GENERATED_ARTIFACT_VIEWS_ENABLED" ]; then
|
||||
if [ "${OPENWORK_EVAL_GENERATED_ARTIFACT_VIEWS_E2E_TEST:-0}" = "1" ]; then
|
||||
DEN_GENERATED_ARTIFACT_VIEWS_ENABLED="true"
|
||||
else
|
||||
DEN_GENERATED_ARTIFACT_VIEWS_ENABLED="false"
|
||||
fi
|
||||
fi
|
||||
case "$DEN_GENERATED_ARTIFACT_VIEWS_ENABLED" in
|
||||
true|false) ;;
|
||||
*) echo "ERROR: DEN_GENERATED_ARTIFACT_VIEWS_ENABLED must be true or false" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--force-install)
|
||||
FORCE_INSTALL=1
|
||||
;;
|
||||
--seed)
|
||||
RUN_SEED=1
|
||||
;;
|
||||
--snapshot)
|
||||
shift
|
||||
DAYTONA_SERVER_SNAPSHOT="${1:?missing snapshot name}"
|
||||
;;
|
||||
--name)
|
||||
shift
|
||||
SANDBOX="${1:?missing sandbox name}"
|
||||
;;
|
||||
--help|-h)
|
||||
sed -n '1,13p' "$0"
|
||||
exit 0
|
||||
;;
|
||||
--*)
|
||||
echo "Unknown option: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ -n "$REF" ]; then
|
||||
echo "Unexpected extra argument: $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
REF="$1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "$REF" ]; then
|
||||
REF="$(git branch --show-current 2>/dev/null || true)"
|
||||
REF="${REF:-$(git rev-parse HEAD)}"
|
||||
fi
|
||||
|
||||
# The ref is interpolated into a remote shell assignment below, so anything
|
||||
# outside git's safe alphabet (or a leading dash) is remote code execution.
|
||||
case "$REF" in
|
||||
""|-*|*[!A-Za-z0-9._/-]*)
|
||||
echo "ERROR: unsafe ref '$REF' — only letters, digits and . _ / - are allowed." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
snapshot_id() {
|
||||
daytona snapshot list -f json | node -e 'const name = process.argv[1]; let input = ""; process.stdin.on("data", (chunk) => input += chunk); process.stdin.on("end", () => { const snapshot = JSON.parse(input).find((item) => item.name === name); if (snapshot) process.stdout.write(snapshot.id || snapshot.name); });' "$1"
|
||||
}
|
||||
|
||||
SNAPSHOT_ID="$(snapshot_id "$DAYTONA_SERVER_SNAPSHOT")"
|
||||
CREATE_ARGS=(--name "$SANDBOX" --auto-stop 60 --public --target "$DAYTONA_TARGET")
|
||||
if [ -n "$SNAPSHOT_ID" ]; then
|
||||
echo "==> Using Daytona server snapshot: $DAYTONA_SERVER_SNAPSHOT"
|
||||
CREATE_ARGS+=(--snapshot "$SNAPSHOT_ID")
|
||||
else
|
||||
echo "==> Daytona server snapshot '$DAYTONA_SERVER_SNAPSHOT' not found; building from Dockerfile."
|
||||
CREATE_ARGS+=(--dockerfile "$ROOT_DIR/.devcontainer/Dockerfile.daytona-server" --cpu 4 --memory 8 --disk 10)
|
||||
fi
|
||||
|
||||
echo "==> Creating server sandbox: $SANDBOX"
|
||||
echo " Ref: $REF"
|
||||
daytona create "${CREATE_ARGS[@]}"
|
||||
|
||||
echo "==> Waiting for sandbox exec readiness..."
|
||||
exec_ready=0
|
||||
for _ in $(seq 1 60); do
|
||||
if daytona exec "$SANDBOX" -- "bash -lc 'true'" >/dev/null 2>&1; then
|
||||
exec_ready=1
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
if [ "$exec_ready" -ne 1 ]; then
|
||||
echo "ERROR: sandbox did not become exec-ready" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DEN_WEB_URL="$(daytona preview-url "$SANDBOX" -p "$DEN_WEB_PORT" --expires 86400 2>/dev/null | grep -v "^time=")"
|
||||
DEN_API_URL="$(daytona preview-url "$SANDBOX" -p "$DEN_API_PORT" --expires 86400 2>/dev/null | grep -v "^time=")"
|
||||
|
||||
# These exact URLs become the Den's public identity (OAuth issuer + MCP
|
||||
# resource). Every `daytona preview-url` call signs a fresh hostname, so a
|
||||
# caller that re-derives them later gets a *different* host and RFC 9728
|
||||
# validating MCP clients (opencode) refuse the mismatched resource. Hand the
|
||||
# baked URLs to the caller through a trusted runner-side file instead; this
|
||||
# write happens on the runner from daytona CLI output only, so sandbox (ref
|
||||
# controlled) output can never influence it.
|
||||
if [ -n "${OPENWORK_DEN_URLS_FILE:-}" ]; then
|
||||
printf 'DEN_WEB_URL=%s\nDEN_API_URL=%s\n' \
|
||||
"$DEN_WEB_URL" "$DEN_API_URL" > "$OPENWORK_DEN_URLS_FILE"
|
||||
fi
|
||||
|
||||
echo "==> Checking out $REF..."
|
||||
daytona exec "$SANDBOX" -- "bash -lc 'set -euo pipefail; cd /workspace; REF=\"$REF\"; FORCE_INSTALL=\"$FORCE_INSTALL\"; git reset --hard HEAD; if git fetch origin \"\$REF\"; then git checkout --detach FETCH_HEAD; else git fetch origin dev --depth 50 || true; git checkout \"\$REF\"; fi; git rev-parse --short HEAD; if [ \"\$FORCE_INSTALL\" = 1 ]; then rm -f .openwork-daytona/pnpm-lock.sha256 .openwork-daytona/den-web-build.tree .openwork-daytona/den-api-assets.tree; fi'"
|
||||
|
||||
echo "==> Uploading server start script..."
|
||||
START_SCRIPT_B64="$(base64 < "$ROOT_DIR/.devcontainer/start-daytona-server.sh" | tr -d '\n')"
|
||||
daytona exec "$SANDBOX" -- "bash -lc 'set -euo pipefail; cd /workspace; mkdir -p .devcontainer; printf %s $START_SCRIPT_B64 | base64 -d > .devcontainer/start-daytona-server.sh; chmod +x .devcontainer/start-daytona-server.sh'"
|
||||
|
||||
echo "==> Starting OpenWork Den server stack..."
|
||||
BOOTSTRAP_ADMIN_EMAILS_B64="$(printf %s "${DEN_BOOTSTRAP_ADMIN_EMAILS:-}" | base64 | tr -d '\n')"
|
||||
daytona exec "$SANDBOX" -- "bash -lc 'set -euo pipefail; cd /workspace; DEN_BOOTSTRAP_ADMIN_EMAILS=\"\$(printf %s $BOOTSTRAP_ADMIN_EMAILS_B64 | base64 -d)\" DEN_GENERATED_ARTIFACT_VIEWS_ENABLED=\"$DEN_GENERATED_ARTIFACT_VIEWS_ENABLED\" DEN_WEB_PUBLIC_URL=\"$DEN_WEB_URL\" DEN_API_PUBLIC_URL=\"$DEN_API_URL\" DEN_WEB_PORT=$DEN_WEB_PORT DEN_API_PORT=$DEN_API_PORT RUN_SEED=$RUN_SEED bash .devcontainer/start-daytona-server.sh'"
|
||||
|
||||
echo "==> Waiting for public Den Web health (up to ${MAX_WAIT}s)..."
|
||||
elapsed=0
|
||||
while [ "$elapsed" -lt "$MAX_WAIT" ]; do
|
||||
if curl -sf "$DEN_WEB_URL/api/den/health" >/dev/null 2>&1; then
|
||||
echo " Den Web ready after ${elapsed}s."
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
elapsed=$((elapsed + 5))
|
||||
printf " %ds...\r" "$elapsed"
|
||||
done
|
||||
|
||||
if [ "$elapsed" -ge "$MAX_WAIT" ]; then
|
||||
echo ""
|
||||
echo "WARNING: Den Web did not become ready within ${MAX_WAIT}s." >&2
|
||||
echo "Check logs:" >&2
|
||||
echo " daytona exec $SANDBOX -- 'tail -120 /tmp/den-api.log'" >&2
|
||||
echo " daytona exec $SANDBOX -- 'tail -120 /tmp/den-web.log'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " Server sandbox ready: $SANDBOX"
|
||||
echo ""
|
||||
echo " Den Web: $DEN_WEB_URL"
|
||||
echo " Den API: $DEN_API_URL"
|
||||
echo ""
|
||||
echo " Start Electron against this server:"
|
||||
echo " bash .devcontainer/test-on-daytona.sh $REF --den-base-url $DEN_WEB_URL --den-api-base-url $DEN_API_URL"
|
||||
echo ""
|
||||
echo " Cleanup:"
|
||||
echo " daytona delete $SANDBOX"
|
||||
echo "============================================"
|
||||
Reference in New Issue
Block a user