Loading Dockerfile +3 −2 Changes for Dockerfile: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -32,5 +32,6 @@ FROM python:3.12-slim COPY --from=build /install /usr/local RUN useradd --create-home --uid 10001 fm USER fm EXPOSE 8082 ENTRYPOINT ["uvicorn", "federation_manager.main:app", "--host", "0.0.0.0", "--port", "8082"] # 8082 is the EWBI partners reach; 8083 serves /internal/* and must stay inside the cluster. EXPOSE 8082 8083 ENTRYPOINT ["python", "-m", "federation_manager.server"] README.md +3 −1 Changes for README.md: 3 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -57,6 +57,8 @@ docker compose up --build ``` That starts Federation Manager on **:8082**, plus PostgreSQL, NATS JetStream and Keycloak. Partners reach the EWBI on 8082. The internal API (`/internal/*`) answers only on 8083, so publishing 8082 never publishes it (`FM_PORT`, `FM_INTERNAL_PORT`). ```bash curl http://localhost:8082/healthz Loading @@ -68,7 +70,7 @@ curl http://localhost:8082/healthz python -m venv .venv && . .venv/bin/activate pip install -e ".[dev]" docker compose -f docker-compose.dev.yaml up -d postgres nats keycloak uvicorn federation_manager.main:app --reload --port 8082 python -m federation_manager.server # EWBI on :8082, /internal/* on :8083 ``` ### Tests Loading docker-compose.yaml +2 −0 Changes for docker-compose.yaml: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -7,6 +7,8 @@ services: restart: unless-stopped ports: - "8082:8082" # /internal/*, kept to this machine - "127.0.0.1:8083:8083" environment: FM_POSTGRES_URL: postgresql+asyncpg://fm:fm@postgres:5432/fm_db FM_NATS_URL: nats://nats:4222 Loading src/federation_manager/core/config.py +13 −1 Changes for src/federation_manager/core/config.py: 13 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ import base64 import binascii from functools import lru_cache from pydantic import SecretStr, field_validator from pydantic import SecretStr, field_validator, model_validator from pydantic_settings import BaseSettings, SettingsConfigDict Loading @@ -15,6 +15,12 @@ class Settings(BaseSettings): hide_input_in_errors=True, ) # Partners reach the EWBI on `port`. `/internal/*` answers only on `internal_port`, # so publishing `port` to the outside never publishes the internal API with it. host: str = "0.0.0.0" port: int = 8082 internal_port: int = 8083 postgres_url: str = "postgresql+asyncpg://fm:fm@localhost:5433/fm_db" postgres_echo: bool = False log_level: str = "INFO" Loading Loading @@ -57,6 +63,12 @@ class Settings(BaseSettings): _decode_key(value.get_secret_value()) return value @model_validator(mode="after") def _internal_port_is_separate(self) -> "Settings": if self.internal_port == self.port: raise ValueError("FM_INTERNAL_PORT must differ from FM_PORT") return self @property def partner_secret_key_bytes(self) -> bytes | None: if self.partner_secret_key is None: Loading src/federation_manager/main.py +2 −0 Changes for src/federation_manager/main.py: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ from federation_manager.core.config import Settings, get_settings from federation_manager.core.logging import configure_logging, get_logger from federation_manager.dependencies import get_local_operator from federation_manager.domain.ports import EwbiClientPort from federation_manager.middleware.internal_port import InternalPortOnlyMiddleware from federation_manager.middleware.topology_hiding import TopologyHidingMiddleware Loading Loading @@ -220,6 +221,7 @@ def create_app(lifespan: Lifespan[FastAPI] | None = None) -> FastAPI: lifespan=lifespan or default_lifespan, ) app.add_middleware(TopologyHidingMiddleware) app.add_middleware(InternalPortOnlyMiddleware, internal_port=get_settings().internal_port) register_exception_handlers(app) app.openapi = _openapi_with_problem_schemas(app) # type: ignore[method-assign] app.include_router(health_router) Loading Loading
Dockerfile +3 −2 Changes for Dockerfile: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -32,5 +32,6 @@ FROM python:3.12-slim COPY --from=build /install /usr/local RUN useradd --create-home --uid 10001 fm USER fm EXPOSE 8082 ENTRYPOINT ["uvicorn", "federation_manager.main:app", "--host", "0.0.0.0", "--port", "8082"] # 8082 is the EWBI partners reach; 8083 serves /internal/* and must stay inside the cluster. EXPOSE 8082 8083 ENTRYPOINT ["python", "-m", "federation_manager.server"]
README.md +3 −1 Changes for README.md: 3 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -57,6 +57,8 @@ docker compose up --build ``` That starts Federation Manager on **:8082**, plus PostgreSQL, NATS JetStream and Keycloak. Partners reach the EWBI on 8082. The internal API (`/internal/*`) answers only on 8083, so publishing 8082 never publishes it (`FM_PORT`, `FM_INTERNAL_PORT`). ```bash curl http://localhost:8082/healthz Loading @@ -68,7 +70,7 @@ curl http://localhost:8082/healthz python -m venv .venv && . .venv/bin/activate pip install -e ".[dev]" docker compose -f docker-compose.dev.yaml up -d postgres nats keycloak uvicorn federation_manager.main:app --reload --port 8082 python -m federation_manager.server # EWBI on :8082, /internal/* on :8083 ``` ### Tests Loading
docker-compose.yaml +2 −0 Changes for docker-compose.yaml: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -7,6 +7,8 @@ services: restart: unless-stopped ports: - "8082:8082" # /internal/*, kept to this machine - "127.0.0.1:8083:8083" environment: FM_POSTGRES_URL: postgresql+asyncpg://fm:fm@postgres:5432/fm_db FM_NATS_URL: nats://nats:4222 Loading
src/federation_manager/core/config.py +13 −1 Changes for src/federation_manager/core/config.py: 13 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ import base64 import binascii from functools import lru_cache from pydantic import SecretStr, field_validator from pydantic import SecretStr, field_validator, model_validator from pydantic_settings import BaseSettings, SettingsConfigDict Loading @@ -15,6 +15,12 @@ class Settings(BaseSettings): hide_input_in_errors=True, ) # Partners reach the EWBI on `port`. `/internal/*` answers only on `internal_port`, # so publishing `port` to the outside never publishes the internal API with it. host: str = "0.0.0.0" port: int = 8082 internal_port: int = 8083 postgres_url: str = "postgresql+asyncpg://fm:fm@localhost:5433/fm_db" postgres_echo: bool = False log_level: str = "INFO" Loading Loading @@ -57,6 +63,12 @@ class Settings(BaseSettings): _decode_key(value.get_secret_value()) return value @model_validator(mode="after") def _internal_port_is_separate(self) -> "Settings": if self.internal_port == self.port: raise ValueError("FM_INTERNAL_PORT must differ from FM_PORT") return self @property def partner_secret_key_bytes(self) -> bytes | None: if self.partner_secret_key is None: Loading
src/federation_manager/main.py +2 −0 Changes for src/federation_manager/main.py: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ from federation_manager.core.config import Settings, get_settings from federation_manager.core.logging import configure_logging, get_logger from federation_manager.dependencies import get_local_operator from federation_manager.domain.ports import EwbiClientPort from federation_manager.middleware.internal_port import InternalPortOnlyMiddleware from federation_manager.middleware.topology_hiding import TopologyHidingMiddleware Loading Loading @@ -220,6 +221,7 @@ def create_app(lifespan: Lifespan[FastAPI] | None = None) -> FastAPI: lifespan=lifespan or default_lifespan, ) app.add_middleware(TopologyHidingMiddleware) app.add_middleware(InternalPortOnlyMiddleware, internal_port=get_settings().internal_port) register_exception_handlers(app) app.openapi = _openapi_with_problem_schemas(app) # type: ignore[method-assign] app.include_router(health_router) Loading