Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ cluster.yaml
external-url-dump.txt
app/__pycache__/
*.pyc
doc/
61 changes: 61 additions & 0 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
"""
import os
from typing import Optional
from urllib.parse import urlparse


def _normalize_path_prefix(value: str) -> str:
prefix = (value or "").strip()
if not prefix or prefix == "/":
return ""
return "/" + prefix.strip("/")


def _path_prefix_from_public_base_url(value: str) -> str:
raw = (value or "").strip()
if not raw:
return ""
if raw.startswith("/"):
return urlparse(raw).path
parsed = urlparse(raw if "://" in raw else f"https://{raw}")
return parsed.path


INSTANCE_TYPES = {
Expand Down Expand Up @@ -47,6 +65,31 @@ def AVAILABLE_IMAGES(self) -> list:

DATABASE_PATH: str = os.getenv("DATABASE_PATH", "/data/amd-oneclick.db")
SESSION_SECRET: str = os.getenv("SESSION_SECRET", "change-me-for-production")
SSO_ENABLED: bool = os.getenv("SSO_ENABLED", "false").lower() in {"1", "true", "yes", "on"}
SSO_PUBLIC_KEY_PEM: Optional[str] = os.getenv("SSO_PUBLIC_KEY_PEM")
SSO_ISSUER: str = os.getenv("SSO_ISSUER", "")
SSO_AUDIENCE: str = os.getenv("SSO_AUDIENCE", "")
SSO_ALGORITHM: str = os.getenv("SSO_ALGORITHM", "RS256")
SSO_ACCESS_COOKIE_NAME: str = os.getenv("SSO_ACCESS_COOKIE_NAME", "sso_access_token")
SSO_REFRESH_COOKIE_NAME: str = os.getenv("SSO_REFRESH_COOKIE_NAME", "sso_refresh_token")
SSO_REFRESH_THRESHOLD_SECONDS: int = int(os.getenv("SSO_REFRESH_THRESHOLD_SECONDS", "300"))
SSO_REFRESH_URL: str = os.getenv("SSO_REFRESH_URL", "/apitest/api/auth/refresh")
SSO_LOGOUT_URL: str = os.getenv("SSO_LOGOUT_URL", "/apitest/api/auth/logout")
SSO_BIND_ENTRY_URL: str = os.getenv("SSO_BIND_ENTRY_URL", "https://aideveloperportal.anruicloud.com/login?returnUrl=")
SSO_BIND_RETURN_QUERY_KEY: str = os.getenv("SSO_BIND_RETURN_QUERY_KEY", "bind")
SSO_AUTO_CREATE_USER: bool = os.getenv("SSO_AUTO_CREATE_USER", "true").lower() in {"1", "true", "yes", "on"}
SSO_DEFAULT_USER_DOMAIN: str = os.getenv("SSO_DEFAULT_USER_DOMAIN", "developer.local")
SSO_CLAIM_NAME_URI: str = os.getenv(
"SSO_CLAIM_NAME_URI",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
)
SSO_CLAIM_EMAIL_URI: str = os.getenv(
"SSO_CLAIM_EMAIL_URI",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
)

REDIS_URL: str = os.getenv("REDIS_URL", "")
REDIS_TOKEN_VERSION_KEY_PREFIX: str = os.getenv("REDIS_TOKEN_VERSION_KEY_PREFIX", "auth:user")

GITHUB_CLIENT_ID: Optional[str] = os.getenv("GITHUB_CLIENT_ID")
GITHUB_CLIENT_SECRET: Optional[str] = os.getenv("GITHUB_CLIENT_SECRET")
Expand Down Expand Up @@ -109,6 +152,10 @@ def AVAILABLE_IMAGES(self) -> list:

SERVICE_HOST: str = os.getenv("SERVICE_HOST", "localhost")
PUBLIC_BASE_URL: str = os.getenv("PUBLIC_BASE_URL", "")
PUBLIC_PATH_PREFIX: str = _normalize_path_prefix(
os.getenv("PUBLIC_PATH_PREFIX", "")
or _path_prefix_from_public_base_url(os.getenv("PUBLIC_BASE_URL", ""))
)
NODE_PORT_BASE: int = int(os.getenv("NODE_PORT_BASE", "30000"))

PYPI_MIRROR: str = "https://pypi.tuna.tsinghua.edu.cn/simple"
Expand Down Expand Up @@ -141,3 +188,17 @@ def AVAILABLE_IMAGES(self) -> list:


settings = Settings()


def validate_settings() -> None:
if not settings.SSO_ENABLED:
return
missing = []
if not settings.SSO_PUBLIC_KEY_PEM:
missing.append("SSO_PUBLIC_KEY_PEM")
if not settings.SSO_ISSUER:
missing.append("SSO_ISSUER")
if not settings.SSO_AUDIENCE:
missing.append("SSO_AUDIENCE")
if missing:
raise RuntimeError(f"SSO is enabled but missing required env vars: {', '.join(missing)}")
2 changes: 2 additions & 0 deletions app/k8s_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ def _get_labels(self, email: str, instance_id: str) -> dict:
}

def _jupyter_base_url(self, instance_id: str) -> str:
if settings.PUBLIC_PATH_PREFIX:
return f"{settings.PUBLIC_PATH_PREFIX}/instances/{instance_id}/"
return f"/instances/{instance_id}/"

def _workspace_host_path(self, instance_id: str) -> str:
Expand Down
Loading