mirror of
https://github.com/different-ai/openwork
synced 2026-04-25 17:15:34 +02:00
fix den-v2 desktop auth handoff parity (#976)
* fix(den-v2): add desktop auth handoff endpoints * fix(den-db): restore desktop handoff grant table * chore(den): disable github deploy workflows
This commit is contained in:
390
.github/workflows/deploy-den-v2.yml
vendored
390
.github/workflows/deploy-den-v2.yml
vendored
@@ -1,387 +1,19 @@
|
||||
name: Deploy Den v2
|
||||
# Deploy Den v2 workflow intentionally disabled.
|
||||
#
|
||||
# Render is responsible for building and deploying the Daytona-first Den v2
|
||||
# control plane, so this repository workflow should not trigger deploys or
|
||||
# mutate Render environment configuration.
|
||||
|
||||
name: Deploy Den v2 (disabled)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- "services/den-v2/**"
|
||||
- "packages/den-db/**"
|
||||
- "packages/utils/**"
|
||||
- ".github/workflows/deploy-den-v2.yml"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
render_service_id:
|
||||
description: "Optional Render service id override for test/staging deploys"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: deploy-den-v2-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
disabled:
|
||||
if: false
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'different-ai/openwork'
|
||||
steps:
|
||||
- name: Validate required secrets
|
||||
env:
|
||||
RENDER_API_KEY: ${{ secrets.RENDER_API_KEY }}
|
||||
RENDER_DEN_CONTROL_PLANE_SERVICE_ID: ${{ inputs.render_service_id || 'srv-d6sajsua2pns7383mis0' }}
|
||||
RENDER_OWNER_ID: ${{ secrets.RENDER_OWNER_ID }}
|
||||
DATABASE_HOST: ${{ secrets.DATABASE_HOST }}
|
||||
DATABASE_USERNAME: ${{ secrets.DATABASE_USERNAME }}
|
||||
DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
|
||||
DEN_BETTER_AUTH_SECRET: ${{ secrets.DEN_BETTER_AUTH_SECRET }}
|
||||
DEN_GITHUB_CLIENT_ID: ${{ secrets.DEN_GITHUB_CLIENT_ID }}
|
||||
DEN_GITHUB_CLIENT_SECRET: ${{ secrets.DEN_GITHUB_CLIENT_SECRET }}
|
||||
DEN_GOOGLE_CLIENT_ID: ${{ secrets.DEN_GOOGLE_CLIENT_ID }}
|
||||
DEN_GOOGLE_CLIENT_SECRET: ${{ secrets.DEN_GOOGLE_CLIENT_SECRET }}
|
||||
DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
|
||||
POLAR_ACCESS_TOKEN: ${{ secrets.POLAR_ACCESS_TOKEN }}
|
||||
POLAR_PRODUCT_ID: ${{ secrets.POLAR_PRODUCT_ID }}
|
||||
POLAR_BENEFIT_ID: ${{ secrets.POLAR_BENEFIT_ID }}
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
DEN_PROVISIONER_MODE: ${{ vars.DEN_PROVISIONER_MODE }}
|
||||
DEN_RENDER_WORKER_PUBLIC_DOMAIN_SUFFIX: ${{ vars.DEN_RENDER_WORKER_PUBLIC_DOMAIN_SUFFIX }}
|
||||
DEN_DAYTONA_WORKER_PROXY_BASE_URL: ${{ vars.DEN_DAYTONA_WORKER_PROXY_BASE_URL }}
|
||||
DEN_POLAR_FEATURE_GATE_ENABLED: ${{ vars.DEN_POLAR_FEATURE_GATE_ENABLED }}
|
||||
- name: Disabled
|
||||
run: |
|
||||
missing=0
|
||||
for key in RENDER_API_KEY RENDER_DEN_CONTROL_PLANE_SERVICE_ID RENDER_OWNER_ID DEN_BETTER_AUTH_SECRET; do
|
||||
if [ -z "${!key}" ]; then
|
||||
echo "::error::Missing required secret: $key"
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
|
||||
for key in DATABASE_HOST DATABASE_USERNAME DATABASE_PASSWORD; do
|
||||
if [ -z "${!key}" ]; then
|
||||
echo "::error::Missing required database secret: $key"
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
|
||||
vanity_suffix="${DEN_RENDER_WORKER_PUBLIC_DOMAIN_SUFFIX:-openwork.studio}"
|
||||
if [ -n "$vanity_suffix" ] && [ -z "$VERCEL_TOKEN" ]; then
|
||||
echo "::error::Missing required secret: VERCEL_TOKEN (required when vanity domains are enabled)"
|
||||
missing=1
|
||||
fi
|
||||
|
||||
feature_enabled="${DEN_POLAR_FEATURE_GATE_ENABLED:-false}"
|
||||
feature_enabled="$(echo "$feature_enabled" | tr '[:upper:]' '[:lower:]')"
|
||||
provisioner_mode="${DEN_PROVISIONER_MODE:-daytona}"
|
||||
provisioner_mode="$(echo "$provisioner_mode" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
if [ "$provisioner_mode" = "daytona" ]; then
|
||||
if [ -z "$DAYTONA_API_KEY" ]; then
|
||||
echo "::error::Missing required secret: DAYTONA_API_KEY (required when DEN_PROVISIONER_MODE=daytona)"
|
||||
missing=1
|
||||
fi
|
||||
|
||||
if [ -z "$DEN_DAYTONA_WORKER_PROXY_BASE_URL" ]; then
|
||||
echo "::error::Missing required variable: DEN_DAYTONA_WORKER_PROXY_BASE_URL (required when DEN_PROVISIONER_MODE=daytona)"
|
||||
missing=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$feature_enabled" = "true" ]; then
|
||||
for key in POLAR_ACCESS_TOKEN POLAR_PRODUCT_ID POLAR_BENEFIT_ID; do
|
||||
if [ -z "${!key}" ]; then
|
||||
echo "::error::Missing required paywall secret: $key"
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$DEN_GITHUB_CLIENT_ID" ] && [ -z "$DEN_GITHUB_CLIENT_SECRET" ]; then
|
||||
echo "::error::Missing required secret: DEN_GITHUB_CLIENT_SECRET (required when DEN_GITHUB_CLIENT_ID is set)"
|
||||
missing=1
|
||||
fi
|
||||
|
||||
if [ -n "$DEN_GITHUB_CLIENT_SECRET" ] && [ -z "$DEN_GITHUB_CLIENT_ID" ]; then
|
||||
echo "::error::Missing required secret: DEN_GITHUB_CLIENT_ID (required when DEN_GITHUB_CLIENT_SECRET is set)"
|
||||
missing=1
|
||||
fi
|
||||
|
||||
if [ -n "$DEN_GOOGLE_CLIENT_ID" ] && [ -z "$DEN_GOOGLE_CLIENT_SECRET" ]; then
|
||||
echo "::error::Missing required secret: DEN_GOOGLE_CLIENT_SECRET (required when DEN_GOOGLE_CLIENT_ID is set)"
|
||||
missing=1
|
||||
fi
|
||||
|
||||
if [ -n "$DEN_GOOGLE_CLIENT_SECRET" ] && [ -z "$DEN_GOOGLE_CLIENT_ID" ]; then
|
||||
echo "::error::Missing required secret: DEN_GOOGLE_CLIENT_ID (required when DEN_GOOGLE_CLIENT_SECRET is set)"
|
||||
missing=1
|
||||
fi
|
||||
|
||||
if [ "$missing" -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Sync Render env vars and deploy latest commit
|
||||
env:
|
||||
RENDER_API_KEY: ${{ secrets.RENDER_API_KEY }}
|
||||
RENDER_DEN_CONTROL_PLANE_SERVICE_ID: ${{ inputs.render_service_id || 'srv-d6sajsua2pns7383mis0' }}
|
||||
RENDER_OWNER_ID: ${{ secrets.RENDER_OWNER_ID }}
|
||||
DATABASE_HOST: ${{ secrets.DATABASE_HOST }}
|
||||
DATABASE_USERNAME: ${{ secrets.DATABASE_USERNAME }}
|
||||
DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
|
||||
DEN_BETTER_AUTH_SECRET: ${{ secrets.DEN_BETTER_AUTH_SECRET }}
|
||||
DEN_GITHUB_CLIENT_ID: ${{ secrets.DEN_GITHUB_CLIENT_ID }}
|
||||
DEN_GITHUB_CLIENT_SECRET: ${{ secrets.DEN_GITHUB_CLIENT_SECRET }}
|
||||
DEN_GOOGLE_CLIENT_ID: ${{ secrets.DEN_GOOGLE_CLIENT_ID }}
|
||||
DEN_GOOGLE_CLIENT_SECRET: ${{ secrets.DEN_GOOGLE_CLIENT_SECRET }}
|
||||
DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
|
||||
DEN_BETTER_AUTH_URL: ${{ vars.DEN_BETTER_AUTH_URL }}
|
||||
DEN_PROVISIONER_MODE: ${{ vars.DEN_PROVISIONER_MODE }}
|
||||
DEN_RENDER_WORKER_PLAN: ${{ vars.DEN_RENDER_WORKER_PLAN }}
|
||||
DEN_RENDER_WORKER_OPENWORK_VERSION: ${{ vars.DEN_RENDER_WORKER_OPENWORK_VERSION }}
|
||||
DEN_CORS_ORIGINS: ${{ vars.DEN_CORS_ORIGINS }}
|
||||
DEN_RENDER_WORKER_PUBLIC_DOMAIN_SUFFIX: ${{ vars.DEN_RENDER_WORKER_PUBLIC_DOMAIN_SUFFIX }}
|
||||
DEN_RENDER_CUSTOM_DOMAIN_READY_TIMEOUT_MS: ${{ vars.DEN_RENDER_CUSTOM_DOMAIN_READY_TIMEOUT_MS }}
|
||||
DEN_VERCEL_API_BASE: ${{ vars.DEN_VERCEL_API_BASE }}
|
||||
DEN_VERCEL_TEAM_ID: ${{ vars.DEN_VERCEL_TEAM_ID }}
|
||||
DEN_VERCEL_TEAM_SLUG: ${{ vars.DEN_VERCEL_TEAM_SLUG }}
|
||||
DEN_VERCEL_DNS_DOMAIN: ${{ vars.DEN_VERCEL_DNS_DOMAIN }}
|
||||
DEN_DAYTONA_API_URL: ${{ vars.DEN_DAYTONA_API_URL }}
|
||||
DEN_DAYTONA_TARGET: ${{ vars.DEN_DAYTONA_TARGET }}
|
||||
DEN_DAYTONA_SNAPSHOT: ${{ vars.DEN_DAYTONA_SNAPSHOT }}
|
||||
DEN_DAYTONA_WORKER_PROXY_BASE_URL: ${{ vars.DEN_DAYTONA_WORKER_PROXY_BASE_URL }}
|
||||
DEN_DAYTONA_SIGNED_PREVIEW_EXPIRES_SECONDS: ${{ vars.DEN_DAYTONA_SIGNED_PREVIEW_EXPIRES_SECONDS }}
|
||||
DEN_DAYTONA_OPENWORK_VERSION: ${{ vars.DEN_DAYTONA_OPENWORK_VERSION }}
|
||||
DEN_POLAR_FEATURE_GATE_ENABLED: ${{ vars.DEN_POLAR_FEATURE_GATE_ENABLED }}
|
||||
DEN_POLAR_API_BASE: ${{ vars.DEN_POLAR_API_BASE }}
|
||||
DEN_POLAR_SUCCESS_URL: ${{ vars.DEN_POLAR_SUCCESS_URL }}
|
||||
DEN_POLAR_RETURN_URL: ${{ vars.DEN_POLAR_RETURN_URL }}
|
||||
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
||||
POLAR_ACCESS_TOKEN: ${{ secrets.POLAR_ACCESS_TOKEN }}
|
||||
POLAR_PRODUCT_ID: ${{ secrets.POLAR_PRODUCT_ID }}
|
||||
POLAR_BENEFIT_ID: ${{ secrets.POLAR_BENEFIT_ID }}
|
||||
run: |
|
||||
python3 <<'PY'
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
api_key = os.environ["RENDER_API_KEY"]
|
||||
service_id = os.environ["RENDER_DEN_CONTROL_PLANE_SERVICE_ID"]
|
||||
owner_id = os.environ["RENDER_OWNER_ID"]
|
||||
openwork_version = os.environ.get("DEN_RENDER_WORKER_OPENWORK_VERSION")
|
||||
worker_plan = os.environ.get("DEN_RENDER_WORKER_PLAN") or "standard"
|
||||
provisioner_mode = (os.environ.get("DEN_PROVISIONER_MODE") or "daytona").strip().lower() or "daytona"
|
||||
configured_cors_origins = os.environ.get("DEN_CORS_ORIGINS") or ""
|
||||
worker_public_domain_suffix = os.environ.get("DEN_RENDER_WORKER_PUBLIC_DOMAIN_SUFFIX") or "openwork.studio"
|
||||
custom_domain_ready_timeout_ms = os.environ.get("DEN_RENDER_CUSTOM_DOMAIN_READY_TIMEOUT_MS") or "240000"
|
||||
vercel_api_base = os.environ.get("DEN_VERCEL_API_BASE") or "https://api.vercel.com"
|
||||
vercel_team_id = os.environ.get("DEN_VERCEL_TEAM_ID") or ""
|
||||
vercel_team_slug = os.environ.get("DEN_VERCEL_TEAM_SLUG") or "prologe"
|
||||
vercel_dns_domain = os.environ.get("DEN_VERCEL_DNS_DOMAIN") or worker_public_domain_suffix
|
||||
vercel_token = os.environ.get("VERCEL_TOKEN") or ""
|
||||
daytona_api_url = os.environ.get("DEN_DAYTONA_API_URL") or "https://app.daytona.io/api"
|
||||
daytona_api_key = os.environ.get("DAYTONA_API_KEY") or ""
|
||||
daytona_target = os.environ.get("DEN_DAYTONA_TARGET") or ""
|
||||
daytona_snapshot = os.environ.get("DEN_DAYTONA_SNAPSHOT") or ""
|
||||
daytona_worker_proxy_base_url = os.environ.get("DEN_DAYTONA_WORKER_PROXY_BASE_URL") or ""
|
||||
daytona_signed_preview_expires_seconds = os.environ.get("DEN_DAYTONA_SIGNED_PREVIEW_EXPIRES_SECONDS") or "86400"
|
||||
daytona_openwork_version = os.environ.get("DEN_DAYTONA_OPENWORK_VERSION") or ""
|
||||
paywall_enabled = (os.environ.get("DEN_POLAR_FEATURE_GATE_ENABLED") or "false").lower() == "true"
|
||||
polar_api_base = os.environ.get("DEN_POLAR_API_BASE") or "https://api.polar.sh"
|
||||
polar_success_url = os.environ.get("DEN_POLAR_SUCCESS_URL") or "https://app.openwork.software"
|
||||
polar_return_url = os.environ.get("DEN_POLAR_RETURN_URL") or polar_success_url
|
||||
polar_access_token = os.environ.get("POLAR_ACCESS_TOKEN") or ""
|
||||
polar_product_id = os.environ.get("POLAR_PRODUCT_ID") or ""
|
||||
polar_benefit_id = os.environ.get("POLAR_BENEFIT_ID") or ""
|
||||
github_client_id = os.environ.get("DEN_GITHUB_CLIENT_ID") or ""
|
||||
github_client_secret = os.environ.get("DEN_GITHUB_CLIENT_SECRET") or ""
|
||||
google_client_id = os.environ.get("DEN_GOOGLE_CLIENT_ID") or ""
|
||||
google_client_secret = os.environ.get("DEN_GOOGLE_CLIENT_SECRET") or ""
|
||||
better_auth_url = os.environ.get("DEN_BETTER_AUTH_URL") or "https://app.openwork.software"
|
||||
|
||||
if bool(github_client_id) != bool(github_client_secret):
|
||||
raise RuntimeError(
|
||||
"DEN_GITHUB_CLIENT_ID and DEN_GITHUB_CLIENT_SECRET must either both be set or both be empty"
|
||||
)
|
||||
|
||||
if bool(google_client_id) != bool(google_client_secret):
|
||||
raise RuntimeError(
|
||||
"DEN_GOOGLE_CLIENT_ID and DEN_GOOGLE_CLIENT_SECRET must either both be set or both be empty"
|
||||
)
|
||||
|
||||
def validate_redirect_url(name: str, value: str):
|
||||
parsed = urllib.parse.urlparse(value)
|
||||
if parsed.scheme not in {"http", "https"} or not parsed.netloc:
|
||||
raise RuntimeError(f"{name} must be an absolute http(s) URL, got: {value}")
|
||||
|
||||
validate_redirect_url("DEN_POLAR_SUCCESS_URL", polar_success_url)
|
||||
validate_redirect_url("DEN_POLAR_RETURN_URL", polar_return_url)
|
||||
validate_redirect_url("DEN_BETTER_AUTH_URL", better_auth_url)
|
||||
|
||||
if provisioner_mode == "daytona":
|
||||
if not daytona_api_key:
|
||||
raise RuntimeError("DEN_PROVISIONER_MODE=daytona requires DAYTONA_API_KEY")
|
||||
if not daytona_worker_proxy_base_url:
|
||||
raise RuntimeError("DEN_PROVISIONER_MODE=daytona requires DEN_DAYTONA_WORKER_PROXY_BASE_URL")
|
||||
validate_redirect_url("DEN_DAYTONA_WORKER_PROXY_BASE_URL", daytona_worker_proxy_base_url)
|
||||
|
||||
if paywall_enabled and (not polar_access_token or not polar_product_id or not polar_benefit_id):
|
||||
raise RuntimeError(
|
||||
"DEN_POLAR_FEATURE_GATE_ENABLED=true requires POLAR_ACCESS_TOKEN, POLAR_PRODUCT_ID, and POLAR_BENEFIT_ID"
|
||||
)
|
||||
|
||||
def normalize_origin(value: str) -> str:
|
||||
trimmed = value.strip()
|
||||
if trimmed == "*":
|
||||
return trimmed
|
||||
return trimmed.rstrip("/")
|
||||
|
||||
def build_cors_origins(raw: str, defaults: list[str]) -> str:
|
||||
candidates: list[str] = []
|
||||
if raw.strip():
|
||||
candidates.extend(raw.split(","))
|
||||
candidates.extend(defaults)
|
||||
|
||||
seen = set()
|
||||
normalized = []
|
||||
for value in candidates:
|
||||
origin = normalize_origin(value)
|
||||
if not origin or origin in seen:
|
||||
continue
|
||||
seen.add(origin)
|
||||
normalized.append(origin)
|
||||
|
||||
if not normalized:
|
||||
raise RuntimeError("Unable to derive CORS_ORIGINS for Den deployment")
|
||||
|
||||
return ",".join(normalized)
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
def request(method: str, path: str, body=None):
|
||||
url = f"https://api.render.com/v1{path}"
|
||||
data = None
|
||||
if body is not None:
|
||||
data = json.dumps(body).encode("utf-8")
|
||||
req = urllib.request.Request(url, data=data, method=method, headers=headers)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=60) as resp:
|
||||
text = resp.read().decode("utf-8")
|
||||
return resp.status, json.loads(text) if text else None
|
||||
except urllib.error.HTTPError as err:
|
||||
text = err.read().decode("utf-8", "replace")
|
||||
raise RuntimeError(f"{method} {path} failed ({err.code}): {text[:600]}")
|
||||
|
||||
_, service = request("GET", f"/services/{service_id}")
|
||||
service_url = (service.get("serviceDetails") or {}).get("url")
|
||||
if not service_url:
|
||||
raise RuntimeError(f"Render service {service_id} has no public URL")
|
||||
|
||||
cors_origins = build_cors_origins(
|
||||
configured_cors_origins,
|
||||
[
|
||||
"https://app.openwork.software",
|
||||
"https://api.openwork.software",
|
||||
service_url,
|
||||
],
|
||||
)
|
||||
|
||||
env_vars = [
|
||||
{"key": "BETTER_AUTH_SECRET", "value": os.environ["DEN_BETTER_AUTH_SECRET"]},
|
||||
{"key": "BETTER_AUTH_URL", "value": better_auth_url},
|
||||
{"key": "GITHUB_CLIENT_ID", "value": github_client_id},
|
||||
{"key": "GITHUB_CLIENT_SECRET", "value": github_client_secret},
|
||||
{"key": "GOOGLE_CLIENT_ID", "value": google_client_id},
|
||||
{"key": "GOOGLE_CLIENT_SECRET", "value": google_client_secret},
|
||||
{"key": "CORS_ORIGINS", "value": cors_origins},
|
||||
{"key": "PROVISIONER_MODE", "value": provisioner_mode},
|
||||
{"key": "RENDER_API_BASE", "value": "https://api.render.com/v1"},
|
||||
{"key": "RENDER_API_KEY", "value": api_key},
|
||||
{"key": "RENDER_OWNER_ID", "value": owner_id},
|
||||
{"key": "RENDER_WORKER_REPO", "value": "https://github.com/different-ai/openwork"},
|
||||
{"key": "RENDER_WORKER_BRANCH", "value": "dev"},
|
||||
{"key": "RENDER_WORKER_ROOT_DIR", "value": "services/den-worker-runtime"},
|
||||
{"key": "RENDER_WORKER_PLAN", "value": worker_plan},
|
||||
{"key": "RENDER_WORKER_REGION", "value": "oregon"},
|
||||
{"key": "RENDER_WORKER_NAME_PREFIX", "value": "den-worker-openwork"},
|
||||
{"key": "RENDER_WORKER_PUBLIC_DOMAIN_SUFFIX", "value": worker_public_domain_suffix},
|
||||
{"key": "RENDER_CUSTOM_DOMAIN_READY_TIMEOUT_MS", "value": custom_domain_ready_timeout_ms},
|
||||
{"key": "RENDER_PROVISION_TIMEOUT_MS", "value": "900000"},
|
||||
{"key": "RENDER_HEALTHCHECK_TIMEOUT_MS", "value": "180000"},
|
||||
{"key": "RENDER_POLL_INTERVAL_MS", "value": "5000"},
|
||||
{"key": "VERCEL_API_BASE", "value": vercel_api_base},
|
||||
{"key": "VERCEL_TOKEN", "value": vercel_token},
|
||||
{"key": "VERCEL_TEAM_ID", "value": vercel_team_id},
|
||||
{"key": "VERCEL_TEAM_SLUG", "value": vercel_team_slug},
|
||||
{"key": "VERCEL_DNS_DOMAIN", "value": vercel_dns_domain},
|
||||
{"key": "POLAR_FEATURE_GATE_ENABLED", "value": "true" if paywall_enabled else "false"},
|
||||
{"key": "POLAR_API_BASE", "value": polar_api_base},
|
||||
{"key": "POLAR_ACCESS_TOKEN", "value": polar_access_token},
|
||||
{"key": "POLAR_PRODUCT_ID", "value": polar_product_id},
|
||||
{"key": "POLAR_BENEFIT_ID", "value": polar_benefit_id},
|
||||
{"key": "POLAR_SUCCESS_URL", "value": polar_success_url},
|
||||
{"key": "POLAR_RETURN_URL", "value": polar_return_url},
|
||||
]
|
||||
|
||||
database_host = os.environ.get("DATABASE_HOST") or ""
|
||||
database_username = os.environ.get("DATABASE_USERNAME") or ""
|
||||
database_password = os.environ.get("DATABASE_PASSWORD") or ""
|
||||
|
||||
env_vars.extend(
|
||||
[
|
||||
{"key": "DATABASE_HOST", "value": database_host},
|
||||
{"key": "DATABASE_USERNAME", "value": database_username},
|
||||
{"key": "DATABASE_PASSWORD", "value": database_password},
|
||||
{"key": "DB_MODE", "value": "planetscale"},
|
||||
]
|
||||
)
|
||||
|
||||
if provisioner_mode == "daytona":
|
||||
env_vars.extend(
|
||||
[
|
||||
{"key": "DAYTONA_API_URL", "value": daytona_api_url},
|
||||
{"key": "DAYTONA_API_KEY", "value": daytona_api_key},
|
||||
{"key": "DAYTONA_TARGET", "value": daytona_target},
|
||||
{"key": "DAYTONA_SNAPSHOT", "value": daytona_snapshot},
|
||||
{"key": "DAYTONA_WORKER_PROXY_BASE_URL", "value": daytona_worker_proxy_base_url},
|
||||
{"key": "DAYTONA_SIGNED_PREVIEW_EXPIRES_SECONDS", "value": daytona_signed_preview_expires_seconds},
|
||||
]
|
||||
)
|
||||
|
||||
if daytona_openwork_version:
|
||||
env_vars.append({"key": "DAYTONA_OPENWORK_VERSION", "value": daytona_openwork_version})
|
||||
|
||||
if openwork_version:
|
||||
env_vars.append({"key": "RENDER_WORKER_OPENWORK_VERSION", "value": openwork_version})
|
||||
|
||||
request("PUT", f"/services/{service_id}/env-vars", env_vars)
|
||||
_, deploy = request("POST", f"/services/{service_id}/deploys", {})
|
||||
deploy_id = deploy.get("id") or (deploy.get("deploy") or {}).get("id")
|
||||
if not deploy_id:
|
||||
raise RuntimeError(f"Unexpected deploy response: {deploy}")
|
||||
|
||||
terminal = {"live", "update_failed", "build_failed", "canceled"}
|
||||
started = time.time()
|
||||
|
||||
while time.time() - started < 1800:
|
||||
_, deploys = request("GET", f"/services/{service_id}/deploys?limit=1")
|
||||
latest = deploys[0]["deploy"] if deploys else None
|
||||
if latest and latest.get("id") == deploy_id and latest.get("status") in terminal:
|
||||
status = latest.get("status")
|
||||
if status != "live":
|
||||
raise RuntimeError(f"Render deploy {deploy_id} ended with {status}")
|
||||
print(f"Render deploy {deploy_id} is live at {service_url}")
|
||||
break
|
||||
time.sleep(10)
|
||||
else:
|
||||
raise RuntimeError(f"Timed out waiting for deploy {deploy_id}")
|
||||
PY
|
||||
echo "deploy-den-v2.yml is intentionally disabled; Render handles Den v2 deploys"
|
||||
|
||||
11
.github/workflows/deploy-den.yml
vendored
11
.github/workflows/deploy-den.yml
vendored
@@ -1,3 +1,8 @@
|
||||
# Deploy Den workflow intentionally disabled.
|
||||
#
|
||||
# Render is responsible for building and deploying the legacy Den service,
|
||||
# so this repository workflow should not trigger any deploy automation.
|
||||
|
||||
name: Deploy Den (disabled)
|
||||
|
||||
on:
|
||||
@@ -10,8 +15,4 @@ jobs:
|
||||
steps:
|
||||
- name: Disabled
|
||||
run: |
|
||||
echo "deploy-den.yml is intentionally disabled"
|
||||
|
||||
# Historical workflow intentionally commented out.
|
||||
# The previous Render deployment automation for the legacy Den service
|
||||
# should not run anymore.
|
||||
echo "deploy-den.yml is intentionally disabled; Render handles Den deploys"
|
||||
|
||||
Reference in New Issue
Block a user