diff --git a/skyvern/config.py b/skyvern/config.py index d0d2c8cc2..6a13c85a2 100644 --- a/skyvern/config.py +++ b/skyvern/config.py @@ -212,6 +212,7 @@ class Settings(BaseSettings): ENABLE_CODE_BLOCK_SELF_HEALING: bool = False PORT: int = 8000 ALLOWED_ORIGINS: list[str] = ["*"] + ALLOWED_ORIGIN_REGEX: str | None = None BLOCKED_HOSTS: list[str] = ["localhost"] ALLOWED_HOSTS: list[str] = [] diff --git a/skyvern/cors.py b/skyvern/cors.py index f9d50f287..5d117941e 100644 --- a/skyvern/cors.py +++ b/skyvern/cors.py @@ -25,3 +25,11 @@ def credentialed_cors_allow_origins(allowed_origins: Sequence[str]) -> list[str] ) return credentialed_origins + + +def credentialed_cors_allow_origin_regex(allowed_origin_regex: str | None) -> str | None: + if allowed_origin_regex is None: + return None + + stripped_origin_regex = allowed_origin_regex.strip() + return stripped_origin_regex or None diff --git a/skyvern/forge/api_app.py b/skyvern/forge/api_app.py index 81436bf0d..579a80f93 100644 --- a/skyvern/forge/api_app.py +++ b/skyvern/forge/api_app.py @@ -26,7 +26,7 @@ from starlette_context.middleware import RawContextMiddleware from starlette_context.plugins.base import Plugin from skyvern.config import _ensure_sqlite_dir, settings -from skyvern.cors import credentialed_cors_allow_origins +from skyvern.cors import credentialed_cors_allow_origin_regex, credentialed_cors_allow_origins from skyvern.exceptions import SkyvernHTTPException from skyvern.forge import app as forge_app from skyvern.forge.forge_app_initializer import start_forge_app @@ -64,6 +64,7 @@ def add_credentialed_cors_middleware(fastapi_app: FastAPI) -> None: allow_credentials=True, allow_methods=["*"], allow_headers=["*"], + allow_origin_regex=credentialed_cors_allow_origin_regex(settings.ALLOWED_ORIGIN_REGEX), ) diff --git a/tests/unit/test_cors.py b/tests/unit/test_cors.py index 93922556f..3712f3559 100644 --- a/tests/unit/test_cors.py +++ b/tests/unit/test_cors.py @@ -1,4 +1,4 @@ -from skyvern.cors import credentialed_cors_allow_origins +from skyvern.cors import credentialed_cors_allow_origin_regex, credentialed_cors_allow_origins def test_credentialed_cors_allow_origins_drops_wildcards() -> None: @@ -10,3 +10,11 @@ def test_credentialed_cors_allow_origins_drops_wildcards() -> None: "", ] ) == ["https://app.example.test"] + + +def test_credentialed_cors_allow_origin_regex_normalizes_blank_values() -> None: + assert credentialed_cors_allow_origin_regex(None) is None + assert credentialed_cors_allow_origin_regex(" ") is None + assert credentialed_cors_allow_origin_regex(r" \Ahttps://app\.example\.test\Z ") == ( + r"\Ahttps://app\.example\.test\Z" + )