Flatten proxy config to a bool (drop the caddy key)
CaddySpec had only `enable` left (path_prefix/host removed; extra_snippets was
unused), so `proxy: { caddy: {} }` was three levels of nesting for a checkbox —
and it invited drift (supabase silently reverted to proxy.caddy.host). Replace it
with a plain `ServiceSpec.proxy: bool`.
- Model: remove ProxySpec/CaddySpec; `proxy: bool = False`. Readers simplified to
`bool(svc.proxy)` (generator, castle-api summaries, CLI info).
- CLI create / dashboard editor + create form: write `proxy: true` / a checkbox.
- Configs migrated to `proxy: true` (and supabase's stale proxy.caddy.host block
removed).
- Docs (registry, dns-and-tls, design, stack guides) + tests/fixtures updated;
also fixed lingering path-model staleness in the stack guides.
This commit is contained in:
@@ -61,7 +61,7 @@ def service_proxy_targets(name: str, svc: ServiceSpec) -> ProxyTargets:
|
||||
port = None
|
||||
if svc.expose and svc.expose.http:
|
||||
port = svc.expose.http.internal.port
|
||||
expose = bool(svc.proxy and svc.proxy.caddy and svc.proxy.caddy.enable)
|
||||
expose = bool(svc.proxy)
|
||||
base_url = getattr(svc.run, "base_url", None)
|
||||
return expose, port, base_url
|
||||
|
||||
|
||||
@@ -145,18 +145,6 @@ class ExposeSpec(BaseModel):
|
||||
http: HttpExposeSpec | None = None
|
||||
|
||||
|
||||
class CaddySpec(BaseModel):
|
||||
# The "expose" checkbox: when present and enabled, the gateway routes
|
||||
# <service-name>.<gateway.domain> to this service (whole host → backend root).
|
||||
# The subdomain is always the service name — rename the service to change it.
|
||||
enable: bool = True
|
||||
extra_snippets: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ProxySpec(BaseModel):
|
||||
caddy: CaddySpec | None = None
|
||||
|
||||
|
||||
# ---------------------
|
||||
# Build spec
|
||||
# ---------------------
|
||||
@@ -277,7 +265,9 @@ class ServiceSpec(BaseModel):
|
||||
run: RunSpec
|
||||
|
||||
expose: ExposeSpec | None = None
|
||||
proxy: ProxySpec | None = None
|
||||
# Expose this service at <service-name>.<gateway.domain> through the gateway
|
||||
# (the subdomain is the service name). False → reachable only at its host:port.
|
||||
proxy: bool = False
|
||||
manage: ManageSpec | None = None
|
||||
defaults: DefaultsSpec | None = None
|
||||
|
||||
|
||||
@@ -58,9 +58,7 @@ def castle_root(tmp_path: Path) -> Generator[Path, None, None]:
|
||||
"health_path": "/health",
|
||||
}
|
||||
},
|
||||
"proxy": {
|
||||
"caddy": {"path_prefix": "/test-svc"},
|
||||
},
|
||||
"proxy": True,
|
||||
"manage": {
|
||||
"systemd": {},
|
||||
},
|
||||
|
||||
@@ -11,12 +11,10 @@ from castle_core.generators.caddyfile import (
|
||||
)
|
||||
from castle_core.manifest import (
|
||||
BuildSpec,
|
||||
CaddySpec,
|
||||
ExposeSpec,
|
||||
HttpExposeSpec,
|
||||
HttpInternal,
|
||||
ProgramSpec,
|
||||
ProxySpec,
|
||||
RunPython,
|
||||
ServiceSpec,
|
||||
)
|
||||
@@ -151,7 +149,7 @@ def _service(port: int, *, expose: bool) -> ServiceSpec:
|
||||
return ServiceSpec(
|
||||
run=RunPython(runner="python", program="svc"),
|
||||
expose=ExposeSpec(http=HttpExposeSpec(internal=HttpInternal(port=port))),
|
||||
proxy=ProxySpec(caddy=CaddySpec()) if expose else None,
|
||||
proxy=expose,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class TestLoadConfig:
|
||||
"""Service has correct proxy spec."""
|
||||
config = load_config(castle_root)
|
||||
svc = config.services["test-svc"]
|
||||
assert svc.proxy.caddy.enable is True # exposed at <name>.<gateway.domain>
|
||||
assert svc.proxy is True # exposed at <name>.<gateway.domain>
|
||||
|
||||
def test_service_run_spec(self, castle_root: Path) -> None:
|
||||
"""Service has correct RunSpec."""
|
||||
|
||||
@@ -5,14 +5,12 @@ from __future__ import annotations
|
||||
import pytest
|
||||
from castle_core.manifest import (
|
||||
BuildSpec,
|
||||
CaddySpec,
|
||||
ProgramSpec,
|
||||
ExposeSpec,
|
||||
HttpExposeSpec,
|
||||
HttpInternal,
|
||||
JobSpec,
|
||||
ManageSpec,
|
||||
ProxySpec,
|
||||
RunCommand,
|
||||
RunPython,
|
||||
RunRemote,
|
||||
@@ -92,9 +90,9 @@ class TestServiceSpec:
|
||||
s = ServiceSpec(
|
||||
id="svc",
|
||||
run=RunPython(runner="python", program="svc"),
|
||||
proxy=ProxySpec(caddy=CaddySpec()),
|
||||
proxy=True,
|
||||
)
|
||||
assert s.proxy.caddy.enable is True
|
||||
assert s.proxy is True
|
||||
|
||||
def test_service_with_manage(self) -> None:
|
||||
"""Service with systemd management."""
|
||||
@@ -185,10 +183,10 @@ class TestModelSerialization:
|
||||
internal=HttpInternal(port=9001), health_path="/health"
|
||||
)
|
||||
),
|
||||
proxy=ProxySpec(caddy=CaddySpec()),
|
||||
proxy=True,
|
||||
manage=ManageSpec(systemd=SystemdSpec()),
|
||||
)
|
||||
data = s.model_dump(exclude_none=True, exclude={"id"})
|
||||
assert data["run"]["runner"] == "python"
|
||||
assert data["expose"]["http"]["internal"]["port"] == 9001
|
||||
assert data["proxy"]["caddy"]["enable"] is True
|
||||
assert data["proxy"] is True
|
||||
|
||||
Reference in New Issue
Block a user