103 lines
3.6 KiB
Bash
Executable File
103 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Create the reusable Daytona secrets volume once. If a local env file is
|
|
# provided, copy it into the mounted volume without printing it.
|
|
#
|
|
# Usage:
|
|
# bash .devcontainer/setup-daytona-secrets-volume.sh [.newtoken] [openai.env]
|
|
|
|
VOLUME_NAME="${DAYTONA_SECRETS_VOLUME:-openwork-eval-secrets}"
|
|
MOUNT_PATH="${DAYTONA_SECRETS_MOUNT:-/daytona-secrets}"
|
|
LOCAL_ENV_FILE="${1:-.newtoken}"
|
|
DEST_ENV_FILE="${2:-openai.env}"
|
|
SANDBOX="openwork-secrets-setup-$(date +%Y%m%d-%H%M%S)"
|
|
SNAPSHOT_NAME="${DAYTONA_EVAL_SNAPSHOT:-openwork-eval-vnc}"
|
|
|
|
volume_field() {
|
|
local name="$1"
|
|
local field="$2"
|
|
daytona volume list -f json | node -e 'const name = process.argv[1]; const field = process.argv[2]; let input = ""; process.stdin.on("data", (chunk) => input += chunk); process.stdin.on("end", () => { const volume = JSON.parse(input).find((item) => item.name === name); if (!volume) process.exit(1); process.stdout.write(String(volume[field] ?? "")); });' "$name" "$field"
|
|
}
|
|
|
|
wait_for_volume_ready() {
|
|
local name="$1"
|
|
local state=""
|
|
|
|
for _ in $(seq 1 60); do
|
|
state="$(volume_field "$name" state 2>/dev/null || true)"
|
|
if [ "$state" = "ready" ]; then
|
|
return 0
|
|
fi
|
|
if [ "$state" = "error" ]; then
|
|
echo "ERROR: volume '$name' is in error state" >&2
|
|
exit 1
|
|
fi
|
|
sleep 5
|
|
done
|
|
|
|
echo "ERROR: volume '$name' did not become ready (last state: ${state:-missing})" >&2
|
|
exit 1
|
|
}
|
|
|
|
if [[ ! "$DEST_ENV_FILE" =~ ^[A-Za-z0-9._-]+\.env$ ]]; then
|
|
echo "ERROR: destination env file must be a simple .env filename, for example openai.env" >&2
|
|
exit 1
|
|
fi
|
|
|
|
cleanup() {
|
|
yes | daytona delete "$SANDBOX" >/dev/null 2>&1 || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
volume_create_output="$(daytona volume create "$VOLUME_NAME" --size 1 2>&1 || true)"
|
|
if [ -n "$volume_create_output" ] && ! printf '%s' "$volume_create_output" | grep -qi "already exists"; then
|
|
printf '%s\n' "$volume_create_output"
|
|
fi
|
|
wait_for_volume_ready "$VOLUME_NAME"
|
|
VOLUME_ID="$(volume_field "$VOLUME_NAME" id)"
|
|
|
|
if [ ! -f "$LOCAL_ENV_FILE" ]; then
|
|
echo "Volume ready: $VOLUME_NAME"
|
|
echo "No local env file found at $LOCAL_ENV_FILE; skipping secret copy."
|
|
exit 0
|
|
fi
|
|
|
|
SECRET_ENV_B64="$(base64 < "$LOCAL_ENV_FILE" | tr -d '\n')"
|
|
|
|
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); });' "$SNAPSHOT_NAME")"
|
|
|
|
if [ -z "$SNAPSHOT_ID" ]; then
|
|
echo "ERROR: Daytona snapshot '$SNAPSHOT_NAME' not found." >&2
|
|
echo "Create it with: bash .devcontainer/create-daytona-openwork-snapshot.sh" >&2
|
|
exit 1
|
|
fi
|
|
|
|
daytona create \
|
|
--name "$SANDBOX" \
|
|
--snapshot "$SNAPSHOT_ID" \
|
|
--volume "${VOLUME_ID}:${MOUNT_PATH}" \
|
|
--auto-stop 15 \
|
|
--public \
|
|
--target us >/dev/null
|
|
|
|
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
|
|
|
|
daytona exec "$SANDBOX" -- "bash -lc 'mkdir -p \"$MOUNT_PATH\" && umask 177 && printf %s \"$SECRET_ENV_B64\" | base64 -d > \"$MOUNT_PATH/$DEST_ENV_FILE\"'" >/dev/null
|
|
daytona exec "$SANDBOX" -- "bash -lc 'test -s \"$MOUNT_PATH/$DEST_ENV_FILE\" && chmod 600 \"$MOUNT_PATH/$DEST_ENV_FILE\"'" >/dev/null
|
|
|
|
echo "Volume ready: $VOLUME_NAME"
|
|
echo "Secret env installed at ${MOUNT_PATH}/${DEST_ENV_FILE}"
|
|
echo "Electron sources every ${MOUNT_PATH}/*.env file by default."
|