Files
ScadaBridge/Directory.Packages.props
T
Joseph Doherty 47850c0f53 feat(health): serve MapZbHealth on site nodes
Site nodes served no health surface at all — gRPC on the HTTP/2-only listener and
/metrics on the HTTP/1.1 one — so nothing outside the cluster could ask a site
node whether it was ready or which half of the pair was active. The family
overview dashboard probes every instance the same way, and this is the one gap.

Three checks, registered in SiteServiceRegistration.Configure (not Program.cs, so
the composition-root tests that build this graph actually cover them) and mapped
by app.MapZbHealth() on the site's HTTP/1.1 listener (default :8084) alongside
/metrics:

  akka-cluster  [Ready]  the shared AkkaClusterHealthCheck. Also carries the
                         cluster-view data (leader/memberCount/...) the dashboard
                         reads, free with ZB.MOM.WW.Health 0.2.0.
  localdb       [Ready]  NEW SiteLocalDbHealthCheck — SELECT 1 through the
                         registered ILocalDb. Site has no EF context; central's
                         DatabaseHealthCheck<ScadaBridgeDbContext> is central-only.
                         Replication state rides along as data ENRICHMENT only:
                         replication is default-OFF, so failing on it would mark
                         every correctly-configured node unready.
  active-node   [Active] NEW SitePairActiveNodeHealthCheck, delegating to
                         IClusterNodeProvider.SelfIsPrimary. Deliberately NOT
                         central's OldestNodeActiveHealthCheck: that one calls
                         SelfIsOldest(cluster) with no role argument and would
                         compute "oldest" across the wrong member set on a mesh
                         carrying more than one site.

Anonymous, as central's are: the site pipeline runs no authentication middleware
and has no FallbackPolicy, so nothing extra was needed.

Also bumps ZB.MOM.WW.Health* 0.1.0 -> 0.2.0 (central gains data.leader for free).

Tests: SiteHealthCheckTests builds the REAL site container and activates every
registration through its factory (exact-set names, one tier tag each, resolved
types, central-only checks absent behind a positive control) plus behaviour for
both new checks. SiteHealthEndpointTests boots the real site Program over
WebApplicationFactory and proves the endpoints are MAPPED — without it, deleting
MapZbHealth would leave every registration test green while site nodes 404'd.

Prereq for scadaproj docs/plans/2026-07-22-overview-dashboard-impl-plan.md Phase 1.
2026-07-24 05:54:30 -04:00

185 lines
12 KiB
XML

<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Akka" Version="1.5.62" />
<PackageVersion Include="Akka.Cluster" Version="1.5.62" />
<PackageVersion Include="Akka.Cluster.Tools" Version="1.5.62" />
<PackageVersion Include="Akka.Remote" Version="1.5.62" />
<PackageVersion Include="Akka.Streams" Version="1.5.62" />
<PackageVersion Include="Akka.Streams.TestKit" Version="1.5.62" />
<PackageVersion Include="Akka.TestKit.Xunit2" Version="1.5.62" />
<PackageVersion Include="bunit" Version="2.0.33-preview" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
<PackageVersion Include="FluentAssertions" Version="8.3.0" />
<!--
gRPC stack raised 2.71.0 -> 2.76.0 (Protobuf 3.29.3 -> 3.34.1) on 2026-07-19.
Forced by ZB.MOM.WW.LocalDb.Replication 0.1.0, whose nuspec floors Grpc.AspNetCore,
Grpc.Net.Client, Grpc.Core.Api and Grpc.Tools at 2.76.0 and Google.Protobuf at 3.34.1.
Below that floor restore fails NU1605 (package downgrade), so this is not optional for
LocalDb adoption.
The SQLitePCLRaw note below deferred exactly this bump as belonging in "their own
reviewed commit" rather than smuggled under a security fix - so it IS its own commit.
Direct consumer surface is narrow: Grpc.AspNetCore only in Host, Grpc.Net.Client only
in Communication. Grpc.Core.Api is pinned explicitly here to keep the whole family on
one version rather than letting it float in transitively.
Not bumped here: Microsoft.Data.SqlClient and Newtonsoft.Json, also named in that note.
Nothing forces them, and they are a data-access change with its own risk profile.
-->
<PackageVersion Include="Google.Protobuf" Version="3.34.1" />
<PackageVersion Include="Grpc.AspNetCore" Version="2.76.0" />
<PackageVersion Include="Grpc.Net.Client" Version="2.76.0" />
<PackageVersion Include="Grpc.Core.Api" Version="2.76.0" />
<PackageVersion Include="Grpc.Tools" Version="2.76.0" />
<PackageVersion Include="MailKit" Version="4.16.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="5.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.0.0" />
<PackageVersion Include="Microsoft.Data.SqlClient" Version="6.0.2" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.7" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageVersion Include="Microsoft.Playwright" Version="1.58.0" />
<PackageVersion Include="Moq" Version="4.20.72" />
<!-- Pinned to the version Akka.NET already pulls transitively (no version-bump ride-along);
used by Commons.Tests contract-lock tests that exercise the Akka default JSON serializer. -->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Novell.Directory.Ldap.NETStandard" Version="3.6.0" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<PackageVersion Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.5.378.106" />
<PackageVersion Include="OpenTelemetry.Api" Version="1.15.3" />
<PackageVersion Include="Serilog" Version="4.3.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageVersion Include="System.CommandLine" Version="2.0.5" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.11.0" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.4" />
<!--
Xunit.SkippableFact provides [SkippableFact] + Skip.IfNot/Skip.If for
xunit v2. The native Skip API (Assert.Skip / Assert.SkipUnless /
Assert.SkipWhen) only exists in xunit v3; xunit 2.9.x lacks it. Used by
Bundle C MSSQL integration tests in ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests
to mark tests as Skipped (not silently Passed) when MSSQL is unreachable.
-->
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.61" />
<PackageVersion Include="ZB.MOM.WW.Health" Version="0.2.0" />
<PackageVersion Include="ZB.MOM.WW.Health.Akka" Version="0.2.0" />
<PackageVersion Include="ZB.MOM.WW.Health.EntityFrameworkCore" Version="0.2.0" />
<PackageVersion Include="ZB.MOM.WW.Telemetry" Version="0.1.0" />
<PackageVersion Include="ZB.MOM.WW.Telemetry.Serilog" Version="0.1.0" />
<PackageVersion Include="ZB.MOM.WW.MxGateway.Client" Version="0.1.1" />
<PackageVersion Include="ZB.MOM.WW.MxGateway.Contracts" Version="0.1.1" />
<PackageVersion Include="ZB.MOM.WW.Configuration" Version="0.1.0" />
<PackageVersion Include="ZB.MOM.WW.Auth.Abstractions" Version="0.1.5" />
<PackageVersion Include="ZB.MOM.WW.Auth.Ldap" Version="0.1.5" />
<PackageVersion Include="ZB.MOM.WW.Auth.ApiKeys" Version="0.1.5" />
<PackageVersion Include="ZB.MOM.WW.Auth.AspNetCore" Version="0.1.5" />
<PackageVersion Include="ZB.MOM.WW.Audit" Version="0.1.0" />
<PackageVersion Include="ZB.MOM.WW.Theme" Version="0.3.1" />
<PackageVersion Include="ZB.MOM.WW.Secrets" Version="0.2.3" />
<PackageVersion Include="ZB.MOM.WW.Secrets.Abstractions" Version="0.2.3" />
<PackageVersion Include="ZB.MOM.WW.Secrets.Ui" Version="0.2.3" />
<PackageVersion Include="ZB.MOM.WW.Secrets.Replicator.SqlServer" Version="0.2.3" />
<PackageVersion Include="ZB.MOM.WW.LocalDb" Version="0.1.3" />
<PackageVersion Include="ZB.MOM.WW.LocalDb.Replication" Version="0.1.3" />
<PackageVersion Include="ZB.MOM.WW.LocalDb.Contracts" Version="0.1.3" />
</ItemGroup>
<!--
GHSA-2m69-gcr7-jv3q (NU1903, high) is on the NATIVE library SQLitePCLRaw.lib.e_sqlite3
2.1.11, pulled in TRANSITIVELY by Microsoft.Data.Sqlite / EntityFrameworkCore.Sqlite.
FIXED PROPERLY 2026-07-18, replacing a NuGetAuditSuppress that had been masking it. The
suppression's stated rationale — "the only patched native lib is the SQLitePCLRaw 3.x line" —
was WRONG: 2.1.12 patches this advisory within the 2.1.x line, so no risky force-override of
the whole family to 3.x is needed. Verified empirically: with the suppression removed and the
pin in place, a forced restore reports no NU1903.
Why the pin and not a Microsoft.Data.Sqlite bump: bumping Sqlite does NOT clear it (even
10.0.10 still references 2.1.11). Pinning the native lib is the fix. Same approach as
ZB.MOM.WW.Secrets and ZB.MOM.WW.LocalDb.
Why this mattered more than it looked: only the Host project resolved a patched 2.1.12 (via
ZB.MOM.WW.Auth.ApiKeys). AuditLog, SiteEventLogging, SiteRuntime, StoreAndForward and the
test projects — the whole site-local SQLite layer — were still resolving the vulnerable
2.1.11, and the suppression hid that everywhere.
Delivered as an explicit <PackageReference> in each SQLite-consuming project rather than via
CentralPackageTransitivePinningEnabled. Enabling transitive pinning globally was tried first
and rejected: it makes every centrally-defined version a hard ceiling for transitive
resolution too, which immediately demanded bumps to Google.Protobuf (3.29.3->3.34.1),
Grpc.Net.Client (2.71.0->2.76.0), Microsoft.Data.SqlClient (6.0.2->6.1.1) and Newtonsoft.Json
(13.0.3->13.0.4). Those may well be worth doing, but they are a gRPC/data-access change to a
production SCADA platform and belong in their own reviewed commit — not smuggled in under a
SQLite security fix.
-->
<ItemGroup>
<PackageVersion Include="SQLitePCLRaw.lib.e_sqlite3" Version="2.1.12" />
</ItemGroup>
<!--
Four NU1903 high-severity advisories (GHSA-23rf-6693-g89p, GHSA-8q5v-6pqq-x66h,
GHSA-cvvh-rhrc-wg4q, GHSA-g8r8-53c2-pm3f) landed in the NuGet audit data against
System.Security.Cryptography.Xml 10.0.7, pulled in TRANSITIVELY by
Microsoft.AspNetCore.DataProtection 10.0.7 (ConfigurationDatabase's DataProtection
key storage). With TreatWarningsAsErrors any FRESH restore — notably the docker
image build — went red (surfaced 2026-07-21; local builds had cached audit data).
Same pattern as SQLitePCLRaw above: pin the vulnerable transitive package to its
patched version (10.0.10) with an explicit <PackageReference> in the one project
where the chain enters (ConfigurationDatabase; every other resolver — AuditLog,
SiteCallAudit, Transport, PerformanceTests, tests — reaches it through that
ProjectReference). Bumping the DataProtection parent instead was tried and
rejected: 10.0.10 floors Microsoft.Extensions.* and (via the EFCore adapter)
Microsoft.EntityFrameworkCore at 10.0.10, forcing a family-wide servicing bump
(NU1605 downgrade errors) that belongs in its own reviewed commit.
-->
<ItemGroup>
<PackageVersion Include="System.Security.Cryptography.Xml" Version="10.0.10" />
</ItemGroup>
<!--
GHSA-pgww-w46g-26qg (NU1902, moderate) on AngleSharp, reached only transitively via bunit
in ZB.MOM.WW.ScadaBridge.CentralUI.Tests. With TreatWarningsAsErrors it made the WHOLE
SOLUTION BUILD RED, so no suite could run and every "0 warnings / green" gate was
unverifiable.
Resolved with a scoped NuGetAuditSuppress in that ONE test project (see its csproj for the
full rationale) — deliberately NOT a version pin here. A pin was tried first and reverted:
AngleSharp >= 1.5.0 is the only patched line, and it changes IHtmlCollection<T>'s indexer,
which makes every bunit build throw MissingMethodException at runtime (33 render tests
failed). Bumping bunit does not help either — even 2.7.2 resolves AngleSharp 1.4.0, which
is still vulnerable. There is no working patched combination upstream today.
-->
</Project>