|
2 | 2 |
|
3 | 3 | from enum import Enum |
4 | 4 | from pydantic import Field, model_validator |
5 | | -from typing import TYPE_CHECKING |
| 5 | +from typing import TYPE_CHECKING, Any |
6 | 6 |
|
7 | 7 |
|
8 | 8 | from netengine.spec.models import CrossWorldPeer, ServiceMirror, SpecModel |
9 | | -from netengine.spec.types import GatewayCrossWorldMode, GatewayRealInternetMode |
| 9 | +from netengine.spec.types import GatewayCrossWorldMode, GatewayRealInternetMode, Lifecycle |
10 | 10 |
|
11 | 11 | if TYPE_CHECKING: |
12 | 12 | from netengine.spec.models import NetEngineSpec |
@@ -105,6 +105,34 @@ def validate_trust_bundle(self) -> "TrustBundle": |
105 | 105 | return self |
106 | 106 |
|
107 | 107 |
|
| 108 | +class WorldManifest(SpecModel): |
| 109 | + """Authority-layer manifest for a NetEngine world. |
| 110 | +
|
| 111 | + The manifest provides a compact authority/spec-domain view of the |
| 112 | + governance, naming, identity, trust, registry, numbering, and boundary |
| 113 | + surfaces that define a world. |
| 114 | + """ |
| 115 | + |
| 116 | + world_id: str = Field(...) |
| 117 | + world_name: str = Field(...) |
| 118 | + lifecycle: Lifecycle = Field(...) |
| 119 | + authority_model: str = Field(...) |
| 120 | + authorities: list[Authority] = Field(default_factory=list) |
| 121 | + dns_root_authority: str = Field(...) |
| 122 | + ca_trust_authority: str = Field(...) |
| 123 | + platform_identity_issuer: str = Field(...) |
| 124 | + inworld_identity_issuer: str = Field(...) |
| 125 | + world_registry_authority: str = Field(...) |
| 126 | + domain_registry_authority: str = Field(...) |
| 127 | + numbering_authority: str = Field(...) |
| 128 | + transit_boundary_authority: str = Field(...) |
| 129 | + real_internet_posture: GatewayRealInternetMode = Field(...) |
| 130 | + cross_world_posture: GatewayCrossWorldMode = Field(...) |
| 131 | + exported_authority_metadata: dict[str, Any] = Field(default_factory=dict) |
| 132 | + importable_authority_metadata: dict[str, Any] = Field(default_factory=dict) |
| 133 | + trust_bundles: list[TrustBundle] = Field(default_factory=list) |
| 134 | + |
| 135 | + |
108 | 136 | class BoundaryPolicy(SpecModel): |
109 | 137 | """Authority-layer policy for traffic and trust at the world boundary.""" |
110 | 138 |
|
@@ -307,3 +335,61 @@ def default_authorities_for_spec(spec: "NetEngineSpec") -> list[Authority]: |
307 | 335 | description="Authority over the application service catalog.", |
308 | 336 | ), |
309 | 337 | ] |
| 338 | + |
| 339 | + |
| 340 | +def _trust_bundles_from_spec(spec: "NetEngineSpec") -> list[TrustBundle]: |
| 341 | + """Derive importable trust bundles from configured cross-world peers.""" |
| 342 | + |
| 343 | + bundles: list[TrustBundle] = [] |
| 344 | + for peer in spec.gateway_portal.cross_world.peers: |
| 345 | + mode = peer.mode |
| 346 | + if mode == GatewayCrossWorldMode.NONE: |
| 347 | + continue |
| 348 | + |
| 349 | + if mode == GatewayCrossWorldMode.FEDERATED and not ( |
| 350 | + peer.trust_anchor_cert or peer.trust_bundle |
| 351 | + ): |
| 352 | + continue |
| 353 | + |
| 354 | + bundles.append( |
| 355 | + TrustBundle( |
| 356 | + peer_id=peer.name, |
| 357 | + peer_name=peer.name, |
| 358 | + mode=mode, |
| 359 | + dns_suffixes=[peer.name], |
| 360 | + peer_root_ca=peer.trust_anchor_cert, |
| 361 | + oidc_issuer=peer.trust_bundle, |
| 362 | + ) |
| 363 | + ) |
| 364 | + |
| 365 | + return bundles |
| 366 | + |
| 367 | + |
| 368 | +def world_manifest_from_spec(spec: "NetEngineSpec") -> WorldManifest: |
| 369 | + """Build an authority-layer world manifest from a parsed NetEngine spec. |
| 370 | +
|
| 371 | + NetEngine specs do not currently expose a dedicated stronger world-id field, |
| 372 | + so the manifest intentionally seeds both identity fields from |
| 373 | + ``spec.metadata.name``. |
| 374 | + """ |
| 375 | + |
| 376 | + authorities = default_authorities_for_spec(spec) |
| 377 | + |
| 378 | + return WorldManifest( |
| 379 | + world_id=spec.metadata.name, |
| 380 | + world_name=spec.metadata.name, |
| 381 | + lifecycle=spec.metadata.lifecycle, |
| 382 | + authority_model="default", |
| 383 | + authorities=authorities, |
| 384 | + dns_root_authority="root-naming", |
| 385 | + ca_trust_authority="trust-root", |
| 386 | + platform_identity_issuer="platform-identity", |
| 387 | + inworld_identity_issuer="inworld-identity", |
| 388 | + world_registry_authority="world-root", |
| 389 | + domain_registry_authority="domain-registry", |
| 390 | + numbering_authority="numbering", |
| 391 | + transit_boundary_authority="transit-boundary", |
| 392 | + real_internet_posture=spec.gateway_portal.real_internet.mode, |
| 393 | + cross_world_posture=spec.gateway_portal.cross_world.mode, |
| 394 | + trust_bundles=_trust_bundles_from_spec(spec), |
| 395 | + ) |
0 commit comments