fix(security): preflight reads the latest sealed artifact; byte[] length predicate untranslatable on SQL Server (#815 live gate)

This commit is contained in:
Joseph Doherty
2026-11-11 03:29:41 -05:00
parent 2a87d96fac
commit 481985e20b
3 changed files with 74 additions and 3 deletions
@@ -4,6 +4,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ZB.MOM.WW.OtOpcUa.Configuration;
using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Runtime.Drivers;
@@ -53,12 +54,15 @@ public sealed class CredentialReferencePreflight(IDbContextFactory<OtOpcUaConfig
var devices = ids.Count == 0
? []
: await db.Devices.AsNoTracking().Where(d => ids.Contains(d.DriverInstanceId)).ToListAsync(ct).ConfigureAwait(false);
// The latest SEALED deployment is what the fleet runs (a failed or in-flight one is not). The empty-blob check
// stays client-side: `byte[].Length` in a predicate is not translatable on SQL Server (#815 live gate — the
// whole scan threw on every boot while the EF InMemory suite passed).
var latestBlob = await db.Deployments.AsNoTracking()
.Where(d => d.ArtifactBlob.Length > 0)
.Where(d => d.Status == DeploymentStatus.Sealed)
.OrderByDescending(d => d.CreatedAtUtc)
.Select(d => d.ArtifactBlob)
.FirstOrDefaultAsync(ct).ConfigureAwait(false);
var deployed = latestBlob is null ? [] : DeploymentArtifact.ParseDriverInstances(latestBlob);
var deployed = latestBlob is not { Length: > 0 } ? [] : DeploymentArtifact.ParseDriverInstances(latestBlob);
return Scan(ruled, devices, deployed);
}