Only serve worker endpoints if secret is set (#691)
Default to `ARCADE_WORKER_SECRET` being unset. This env var must be explicitly set now. Once it is set, the `worker/` endpoints will be served.
This commit is contained in:
parent
a921b76ce9
commit
44660d18ce
7 changed files with 38 additions and 18 deletions
|
|
@ -383,6 +383,7 @@ def start_server_process(entrypoint: str, debug: bool = False) -> tuple[subproce
|
|||
"ARCADE_SERVER_PORT": str(port),
|
||||
"ARCADE_SERVER_TRANSPORT": "http",
|
||||
"ARCADE_AUTH_DISABLED": "true",
|
||||
"ARCADE_WORKER_SECRET": "temp-validation-secret",
|
||||
}
|
||||
|
||||
cmd = [sys.executable, entrypoint]
|
||||
|
|
|
|||
|
|
@ -142,8 +142,8 @@ class ArcadeSettings(BaseSettings):
|
|||
description="Disable authentication",
|
||||
)
|
||||
server_secret: str | None = Field(
|
||||
default="dev",
|
||||
description="Server secret",
|
||||
default=None,
|
||||
description="Server secret for worker endpoints (required to enable worker routes)",
|
||||
validation_alias="ARCADE_WORKER_SECRET",
|
||||
)
|
||||
environment: str = Field(
|
||||
|
|
|
|||
|
|
@ -123,15 +123,14 @@ def create_arcade_mcp(
|
|||
**kwargs: Any,
|
||||
) -> FastAPI:
|
||||
"""
|
||||
Create a FastAPI app exposing Arcade Worker and MCP HTTP endpoints.
|
||||
Create a FastAPI app exposing MCP HTTP endpoints
|
||||
and Arcade Worker endpoints if a secret is provided.
|
||||
|
||||
MCP is always enabled in this integrated application.
|
||||
"""
|
||||
if mcp_settings is None:
|
||||
mcp_settings = MCPSettings.from_env()
|
||||
secret = mcp_settings.arcade.server_secret
|
||||
if secret is None:
|
||||
secret = "dev" # noqa: S105
|
||||
|
||||
otel_handler = OTELHandler(
|
||||
enable=otel_enable,
|
||||
|
|
@ -180,13 +179,15 @@ def create_arcade_mcp(
|
|||
app.add_middleware(AddTrailingSlashToPathMiddleware)
|
||||
|
||||
# Worker endpoints
|
||||
worker = FastAPIWorker(
|
||||
app=app,
|
||||
secret=secret,
|
||||
disable_auth=mcp_settings.arcade.auth_disabled,
|
||||
otel_meter=otel_handler.get_meter(),
|
||||
)
|
||||
worker.catalog = catalog
|
||||
if secret is not None:
|
||||
worker = FastAPIWorker(
|
||||
app=app,
|
||||
secret=secret,
|
||||
disable_auth=mcp_settings.arcade.auth_disabled,
|
||||
otel_meter=otel_handler.get_meter(),
|
||||
)
|
||||
worker.catalog = catalog
|
||||
logger.info("Worker routes enabled at /worker/* (ARCADE_WORKER_SECRET is set)")
|
||||
|
||||
class _MCPASGIProxy:
|
||||
def __init__(self, parent_app: FastAPI):
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "arcade-mcp-server"
|
||||
version = "1.8.0"
|
||||
version = "1.9.0"
|
||||
description = "Model Context Protocol (MCP) server framework for Arcade.dev"
|
||||
readme = "README.md"
|
||||
authors = [{ name = "Arcade.dev" }]
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ def start_mcp_server(
|
|||
"ARCADE_SERVER_PORT": str(port),
|
||||
"ARCADE_SERVER_TRANSPORT": "http",
|
||||
"ARCADE_AUTH_DISABLED": "true",
|
||||
"ARCADE_WORKER_SECRET": "test-secret-e2e",
|
||||
}
|
||||
|
||||
cmd = ["uv", "run", entrypoint_path, "http"]
|
||||
|
|
|
|||
|
|
@ -44,12 +44,17 @@ def mock_router():
|
|||
|
||||
@pytest.fixture
|
||||
def base_worker(mock_router):
|
||||
# Save original value
|
||||
original_secret = os.environ.get("ARCADE_WORKER_SECRET")
|
||||
# Set env var temporarily for testing secret loading
|
||||
os.environ["ARCADE_WORKER_SECRET"] = "test_secret_env" # noqa: S105
|
||||
worker = BaseWorker()
|
||||
worker.register_routes(mock_router) # Register routes using the mock router
|
||||
# Clean up env var
|
||||
del os.environ["ARCADE_WORKER_SECRET"]
|
||||
# Restore original value
|
||||
if original_secret is not None:
|
||||
os.environ["ARCADE_WORKER_SECRET"] = original_secret
|
||||
else:
|
||||
del os.environ["ARCADE_WORKER_SECRET"]
|
||||
return worker
|
||||
|
||||
|
||||
|
|
@ -68,20 +73,32 @@ def test_base_worker_init_with_secret():
|
|||
|
||||
|
||||
def test_base_worker_init_with_env_secret():
|
||||
original_secret = os.environ.get("ARCADE_WORKER_SECRET")
|
||||
os.environ["ARCADE_WORKER_SECRET"] = "env_secret_value" # noqa: S105
|
||||
worker = BaseWorker()
|
||||
assert worker.secret == "env_secret_value" # noqa: S105
|
||||
assert not worker.disable_auth
|
||||
del os.environ["ARCADE_WORKER_SECRET"]
|
||||
|
||||
# Restore secret to original if it was set
|
||||
if original_secret is not None:
|
||||
os.environ["ARCADE_WORKER_SECRET"] = original_secret
|
||||
else:
|
||||
del os.environ["ARCADE_WORKER_SECRET"]
|
||||
|
||||
|
||||
def test_base_worker_init_no_secret_raises_error():
|
||||
# Ensure env var is not set
|
||||
# Ensure secret is not set
|
||||
original_secret = os.environ.get("ARCADE_WORKER_SECRET")
|
||||
if "ARCADE_WORKER_SECRET" in os.environ:
|
||||
del os.environ["ARCADE_WORKER_SECRET"]
|
||||
|
||||
with pytest.raises(ValueError, match="No secret provided for worker"):
|
||||
BaseWorker()
|
||||
|
||||
# Restore secret if it was set
|
||||
if original_secret is not None:
|
||||
os.environ["ARCADE_WORKER_SECRET"] = original_secret
|
||||
|
||||
|
||||
def test_base_worker_init_disable_auth():
|
||||
worker = BaseWorker(disable_auth=True)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "arcade-mcp"
|
||||
version = "1.5.3"
|
||||
version = "1.5.4"
|
||||
description = "Arcade.dev - Tool Calling platform for Agents"
|
||||
readme = "README.md"
|
||||
license = {file = "LICENSE"}
|
||||
|
|
|
|||
Loading…
Reference in a new issue