fix(map): complete live Cesium provider path

This commit is contained in:
DCCONSTRUCTIONS
2026-07-29 17:25:07 +03:00
parent f2a4dfe863
commit 5a06194962
3 changed files with 66 additions and 16 deletions
@@ -1,6 +1,7 @@
# Mission Core Map Page + Cesium integration plan # Mission Core Map Page + Cesium integration plan
Status: proposed for product-owner acceptance, 2026-07-29 Status: M0–M3 implemented for the local operator contour; operational
acceptance in progress, 2026-07-29
## Objective ## Objective
@@ -144,9 +145,9 @@ browser cache, per-application TileCache, Docker volume or a second Gateway.
### Shared renderer gate ### Shared renderer gate
`@nodedc/page-patterns` already publishes the runtime-neutral Map Page `@nodedc/page-patterns` publishes the runtime-neutral Map Page definition and
definition, but the Cesium adapter is not a published package. Production reuse `@nodedc/map-cesium-react@0.1.0` now owns the shared Cesium adapter consumed by
requires a shared reviewed package for: Mission Core. The package boundary covers:
- provider startup and independent imagery/terrain/buildings readiness; - provider startup and independent imagery/terrain/buildings readiness;
- Gateway-proxied Cesium resource creation; - Gateway-proxied Cesium resource creation;
@@ -155,16 +156,17 @@ requires a shared reviewed package for:
- elevated target and label presentation; - elevated target and label presentation;
- camera and cache-intent application. - camera and cache-intent application.
Foundry and Mission Core must consume the same package revision. Copying the Foundry and Mission Core must remain on the same reviewed package revision.
Foundry application renderer into Mission Core is rejected. Cesium remains a Copying the Foundry application renderer into Mission Core remains rejected.
lazy chunk loaded only when the map workspace opens. Cesium is a lazy chunk loaded only when the map workspace opens.
## Credential and control-plane decision ## Credential and control-plane decision
Mission Core does not need to receive a Cesium token to render the map. The Mission Core does not need to receive a Cesium token to render the map. The
existing platform token remains owned by Platform Map Gateway, and Mission Core existing platform token remains owned by Platform Map Gateway, and Mission Core
uses it only after Gateway reports a configured/verified state. The current uses it only after Gateway reports a configured/verified state. The connected
network check did not independently verify that state. local Gateway reports `ionConfigured=true` and serves the canonical assets
without exposing credentials.
The proposed `API и ключи` settings section is a write-only Platform The proposed `API и ключи` settings section is a write-only Platform
control-plane client: control-plane client:
@@ -335,15 +337,23 @@ unbounded reconnect loops.
## Current blockers and evidence ## Current blockers and evidence
1. The Cesium adapter is not currently available through a published shared 1. The shared Cesium adapter, Mission Core BFF and real map-first workspace are
package; exact code reuse is blocked until that boundary exists. admitted. Browser acceptance on `127.0.0.1:8000` reports `Карта готова`;
2. Mission Core lacks authenticated admin authority, so platform token rotation imagery, terrain and 3D buildings each report `Готов`, with no blocking map
error.
2. The connected Gateway is configured with assets `1`, `2` and `96188`.
Rendering the acceptance viewport increased the persistent live-cache count
from 3270 to 3282 without a browser credential or direct provider route.
3. Mission Core lacks authenticated admin authority, so platform token rotation
cannot be exposed safely yet. cannot be exposed safely yet.
3. K1 currently has no admitted geodetic anchor, so live scanner targets are a 4. K1 currently has no admitted geodetic anchor, so live scanner targets are a
later data-contract slice. later data-contract slice.
4. From the current Mac network, direct safe probes to the expected private 5. From the current Mac network, direct safe probes to the expected private
Synology Map Gateway/Platform/AMD health endpoints timed out. End-to-end Synology Map Gateway/Platform/AMD health endpoints timed out. End-to-end
acceptance requires the intended LAN route; no address will be hard-coded to NAS/cache-only acceptance still requires the intended LAN route. The
currently connected development Gateway uses a persistent local Docker
volume, so it proves the browser/BFF/Gateway/provider contract but not the
final Synology failover path. No address is hard-coded in frontend state to
hide this condition. hide this condition.
None of these blockers requires a new product window, Engine embedding, None of these blockers requires a new product window, Engine embedding,
+6 -1
View File
@@ -22,6 +22,7 @@ ALLOWED_ION_ASSET_IDS: Final = frozenset({1, 2, 96188})
SAFE_ERROR_CODE = re.compile(r"^[a-z][a-z0-9_]{0,95}$") SAFE_ERROR_CODE = re.compile(r"^[a-z][a-z0-9_]{0,95}$")
MAX_JSON_RESPONSE_BYTES: Final = 1024 * 1024 MAX_JSON_RESPONSE_BYTES: Final = 1024 * 1024
MAX_CACHE_TARGET_LENGTH: Final = 8192 MAX_CACHE_TARGET_LENGTH: Final = 8192
BING_GATEWAY_KEY_MARKER: Final = "nodedc-gateway"
REQUEST_HEADER_ALLOWLIST: Final = frozenset( REQUEST_HEADER_ALLOWLIST: Final = frozenset(
{ {
@@ -325,7 +326,11 @@ def _validate_cache_target(target_url: str) -> None:
) )
if any( if any(
key.lower() in CREDENTIAL_QUERY_KEYS key.lower() in CREDENTIAL_QUERY_KEYS
for key, _ in parse_qsl(parsed.query, keep_blank_values=True) and not (
key.lower() == "key"
and value == BING_GATEWAY_KEY_MARKER
)
for key, value in parse_qsl(parsed.query, keep_blank_values=True)
): ):
raise HTTPException( raise HTTPException(
status_code=422, status_code=422,
+35
View File
@@ -250,6 +250,41 @@ def test_cache_rejects_credentials_non_https_and_non_loopback_clients() -> None:
assert not requests assert not requests
def test_cache_accepts_only_the_public_bing_gateway_key_marker() -> None:
service, requests = _service(
lambda request: httpx.Response(
200,
headers={"content-type": "application/json"},
content=b"{}",
)
)
accepted = asyncio.run(
service.proxy_cache(
_request("/api/v1/map/gateway/cache"),
target_url=(
"https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial"
"?key=nodedc-gateway"
),
)
)
assert isinstance(accepted, StreamingResponse)
assert requests[0].url.params["url"].endswith("key=nodedc-gateway")
with pytest.raises(HTTPException) as exc_info:
asyncio.run(
service.proxy_cache(
_request("/api/v1/map/gateway/cache"),
target_url=(
"https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial"
"?key=browser-secret"
),
)
)
assert exc_info.value.status_code == 422
def test_asset_route_is_a_fixed_allowlist() -> None: def test_asset_route_is_a_fixed_allowlist() -> None:
service, requests = _service( service, requests = _service(
lambda request: httpx.Response( lambda request: httpx.Response(