refactor(host): extract MapOtOpcUaMeshGrpcServices (one authority for the five mesh maps)

Behaviour-preserving: Program.cs:743-784 collapses to a single call, same gates,
same order, every existing per-map rationale comment carried over. A new
endpoint-metadata census (MeshGrpcAnonymousMetadataTests) drives the SAME
production mapper across all three role shapes (admin-only / driver-only /
fused), so the guard can never assert a shape production no longer has -
archreview 03/S14, T1.
This commit is contained in:
Joseph Doherty
2026-08-20 09:42:49 -04:00
parent a011a53329
commit 6dab72a479
3 changed files with 253 additions and 42 deletions
+6 -42
View File
@@ -740,48 +740,12 @@ if (hasAdmin)
app.MapOtOpcUaDeployApi(app.Configuration);
}
// Passive LocalDb sync endpoint. Gated on the same port check that bound the listener, so a
// default-OFF or admin-only graph carries no sync surface whatsoever. Mapping it would be safe
// even unauthenticated — LocalDbSyncAuthInterceptor fail-closes with no ApiKey configured — but
// not mapping it at all is the stronger default.
if (hasDriver && syncListenPort > 0)
{
app.MapZbLocalDbSync();
}
// Central config-serve artifact endpoint (per-cluster mesh Phase 3). Mapped only on admin-role
// nodes (which hold the central SQL connection) and only when a dedicated h2c port is bound. The
// ConfigServeAuthInterceptor is the ONLY inbound auth and fail-closes with no ConfigServe:ApiKey.
if (hasAdmin && configServeGrpcPort > 0)
{
app.MapGrpcService<DeploymentArtifactGrpcService>();
// Central command ingress (mesh gRPC command plane): the node→central deployment ack. It
// rides the SAME listener rather than claiming a port of its own — a second cleartext h2c port
// would buy nothing but another firewall rule, and both endpoints are admin-role and dialled by
// the same driver nodes. Deliberately NOT gated on MeshTransport:Mode: mapping it under Dps
// costs nothing (nothing dials it) whereas gating it would mean flipping the mode on a running
// fleet requires a central restart before any node can ack — the same reasoning that registers
// CentralCommunicationActor in both modes. CentralCommandAuthInterceptor (added at AddGrpc
// above) is the ONLY inbound auth and fail-closes per cluster.
app.MapGrpcService<CentralCommandGrpcService>();
}
// Driver-node live-telemetry stream (per-cluster mesh Phase 5). Central dials in; gated by
// TelemetryStreamAuthInterceptor (fail-closed on empty Telemetry:ApiKey).
//
// The node-side command endpoint (mesh gRPC command plane, Phase 1) rides the SAME driver-role
// h2c listener rather than claiming a fourth port: central already dials this node here, both
// directions are per-cluster-keyed, and a separate port would be one more thing to open on every
// site firewall for no isolation gain. Mapping it is what makes MeshCommandAuthInterceptor live —
// it is registered above and is a pass-through until a call matches this service's method prefix.
// It fail-closes with no MeshTransport:GrpcPsk, so an operator who maps the service without setting
// a key gets a closed endpoint, not an open one.
if (hasDriver && telemetryListenPort > 0)
{
app.MapGrpcService<TelemetryStreamGrpcService>();
app.MapGrpcService<NodeCommandGrpcService>();
}
// Mesh gRPC ingress: the LocalDb passive sync endpoint, the ConfigServe artifact + central
// command endpoints, and the telemetry-stream + node-command endpoints. Extracted to
// MeshGrpcEndpoints so a standing census test drives the SAME production mapping (see that
// file's remarks — archreview 03/S14).
app.MapOtOpcUaMeshGrpcServices(
hasAdmin, hasDriver, syncListenPort, configServeGrpcPort, telemetryListenPort);
app.MapOtOpcUaHealth();
app.MapOtOpcUaMetrics();