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:
2026-06-30 21:23:14 -07:00
parent f14ef3f40b
commit 770574f575
20 changed files with 47 additions and 77 deletions

View File

@@ -8,14 +8,12 @@ import subprocess
from castle_cli.config import REPOS_DIR, load_config, save_config
from castle_cli.manifest import (
BuildSpec,
CaddySpec,
DefaultsSpec,
ExposeSpec,
HttpExposeSpec,
HttpInternal,
ManageSpec,
ProgramSpec,
ProxySpec,
RunPython,
ServiceSpec,
SystemdSpec,
@@ -121,7 +119,7 @@ def run_create(args: argparse.Namespace) -> int:
health_path="/health",
)
),
proxy=ProxySpec(caddy=CaddySpec()), # expose at <name>.<gateway.domain>
proxy=True, # expose at <name>.<gateway.domain>
manage=ManageSpec(systemd=SystemdSpec()),
# python-fastapi scaffold reads env_prefix MY_SERVICE_ — map castle's
# computed port/data dir to those vars (explicit, no hidden injection).

View File

@@ -11,14 +11,12 @@ import argparse
from castle_cli.config import load_config, save_config
from castle_cli.manifest import (
CaddySpec,
DefaultsSpec,
ExposeSpec,
HttpExposeSpec,
HttpInternal,
JobSpec,
ManageSpec,
ProxySpec,
RunCommand,
RunPython,
ServiceSpec,
@@ -62,7 +60,7 @@ def run_service_create(args: argparse.Namespace) -> int:
run = _run_spec(args.runner, args.run or args.program or name, name)
expose = None
proxy = None
proxy = False
if args.port is not None:
expose = ExposeSpec(
http=HttpExposeSpec(
@@ -70,9 +68,8 @@ def run_service_create(args: argparse.Namespace) -> int:
health_path=args.health,
)
)
if not args.no_proxy:
# Expose at <name>.<gateway.domain> (the subdomain is the service name).
proxy = ProxySpec(caddy=CaddySpec())
# Expose at <name>.<gateway.domain> (the subdomain is the service name).
proxy = not args.no_proxy
config.services[name] = ServiceSpec(
id=name,
@@ -90,7 +87,7 @@ def run_service_create(args: argparse.Namespace) -> int:
print(f" runs: {args.runner} ({args.run or args.program or name})")
if expose:
print(f" port: {args.port}")
if proxy and proxy.caddy:
if proxy:
print(f" subdomain: {name}.<gateway.domain>")
print(f"\nNext: castle service deploy {name} && castle service start {name}")
return 0

View File

@@ -119,7 +119,7 @@ def run_info(args: argparse.Namespace) -> int:
print(f" {BOLD}port{RESET}: {http.internal.port}")
if http.health_path:
print(f" {BOLD}health{RESET}: {http.health_path}")
if service.proxy and service.proxy.caddy and service.proxy.caddy.enable:
if service.proxy:
print(f" {BOLD}subdomain{RESET}: {name}.<gateway.domain>")
if service.manage and service.manage.systemd:
sd = service.manage.systemd

View File

@@ -3,7 +3,6 @@
from castle_core.manifest import * # noqa: F401, F403
from castle_core.manifest import ( # noqa: F401 — explicit re-exports for type checkers
BuildSpec,
CaddySpec,
Capability,
CommandsSpec,
DefaultsSpec,
@@ -15,7 +14,6 @@ from castle_core.manifest import ( # noqa: F401 — explicit re-exports for typ
JobSpec,
ManageSpec,
ProgramSpec,
ProxySpec,
ReadinessHttpGet,
RestartPolicy,
RunBase,