diff --git a/compose.coolify.esignet.yaml b/compose.coolify.esignet.yaml index 3df0274..e4b0c52 100644 --- a/compose.coolify.esignet.yaml +++ b/compose.coolify.esignet.yaml @@ -85,7 +85,6 @@ services: esignet-database: {condition: service_healthy} esignet-redis: {condition: service_healthy} labels: - solmara.lab.host: ${SOLMARA_ESIGNET_PUBLIC_HOST:-esignet.solmara.registrystack.org} solmara.rollout.slot: authority-cells esignet-ui: @@ -99,6 +98,21 @@ services: solmara.lab.host: ${SOLMARA_ESIGNET_UI_PUBLIC_HOST:-esignet-ui.solmara.registrystack.org} solmara.rollout.slot: authority-cells + # eSignet answers only under /v1/esignet, so the issuer origin would publish + # neither its OpenID discovery document nor its RFC 8414 authorization-server + # metadata. The UI image is a host-agnostic reverse proxy that serves both at + # the root and forwards /v1/esignet, so it also fronts the issuer origin. + esignet-edge: + image: ${SOLMARA_ESIGNET_UI_IMAGE:?set digest-pinned eSignet UI image} + environment: + SOLMARA_ESIGNET_PUBLIC_HOST: ${SOLMARA_ESIGNET_PUBLIC_HOST:-esignet.solmara.registrystack.org} + SOLMARA_ESIGNET_UI_PUBLIC_HOST: ${SOLMARA_ESIGNET_UI_PUBLIC_HOST:-esignet-ui.solmara.registrystack.org} + depends_on: + esignet: {condition: service_started} + labels: + solmara.lab.host: ${SOLMARA_ESIGNET_PUBLIC_HOST:-esignet.solmara.registrystack.org} + solmara.rollout.slot: authority-cells + esignet-seed: image: ${SOLMARA_ESIGNET_SEED_IMAGE:?set digest-pinned eSignet seed image} restart: "no" diff --git a/scripts/test_hosted_esignet_topology.py b/scripts/test_hosted_esignet_topology.py index f956194..d70fc87 100644 --- a/scripts/test_hosted_esignet_topology.py +++ b/scripts/test_hosted_esignet_topology.py @@ -47,9 +47,15 @@ def test_compose_is_a_standalone_esignet_app(self) -> None: "esignet-redis", "esignet", "esignet-ui", + "esignet-edge", "esignet-seed", }, ) + # The issuer origin is fronted by the proxy image, not by eSignet + # itself, so its discovery documents are reachable where the issuer + # says they are. + self.assertEqual(services["esignet-edge"]["image"], services["esignet-ui"]["image"]) + self.assertNotIn("solmara.lab.host", services["esignet"]["labels"]) self.assertNotIn("portal", services) self.assertEqual( services["esignet"]["environment"]["REGISTRY_MINT_TOKEN_ENDPOINT"], diff --git a/scripts/test_runtime_topology.py b/scripts/test_runtime_topology.py index 453f57f..8a2b692 100644 --- a/scripts/test_runtime_topology.py +++ b/scripts/test_runtime_topology.py @@ -747,7 +747,14 @@ def test_hosted_esignet_is_standalone_and_core_portal_owns_login_config( services = esignet["services"] self.assertEqual( set(services), - {"esignet-database", "esignet-redis", "esignet", "esignet-ui", "esignet-seed"}, + { + "esignet-database", + "esignet-redis", + "esignet", + "esignet-ui", + "esignet-edge", + "esignet-seed", + }, ) self.assertNotIn("portal", services) @@ -800,6 +807,23 @@ def test_hosted_esignet_seeder_runs_once(self) -> None: esignet = yaml.safe_load(esignet_path.read_text(encoding="utf-8")) self.assertEqual(esignet["services"]["esignet-seed"].get("restart"), "no") + def test_hosted_esignet_publishes_discovery_at_its_issuer_root(self) -> None: + """eSignet declares its issuer as the bare public origin but the Spring + service answers only under `/v1/esignet`, so routing the public host + straight at it leaves `{issuer}/.well-known/openid-configuration` and the + RFC 8414 authorization-server document unserved. The UI image is a + host-agnostic reverse proxy that publishes both, so the public host + belongs to an edge instance of it and the service stays unrouted.""" + esignet_path = SCRIPT.parents[1] / "compose.coolify.esignet.yaml" + services = yaml.safe_load(esignet_path.read_text(encoding="utf-8"))["services"] + edge = services["esignet-edge"] + self.assertEqual(edge["image"], services["esignet-ui"]["image"]) + self.assertEqual( + edge["labels"]["solmara.lab.host"], + "${SOLMARA_ESIGNET_PUBLIC_HOST:-esignet.solmara.registrystack.org}", + ) + self.assertNotIn("solmara.lab.host", services["esignet"].get("labels") or {}) + def test_bruno_workspace_covers_only_the_eight_governed_v2_lookups(self) -> None: relay_requests = SCRIPT.parents[1] / "requests/registry-lab/50 - Relay V2" rendered = "\n".join(