using ZB.MOM.WW.Configuration; using ZB.MOM.WW.GalaxyRepository; namespace ZB.MOM.WW.MxGateway.Server.Configuration; /// /// Gateway-side startup validation for the shared . The /// ZB.MOM.WW.GalaxyRepository package binds the options but deliberately ships no validator /// (see A2-galaxyrepository-adoption-handoff.md); the gateway owns the rule because it is the /// process that writes the snapshot. When persistence is on, the snapshot path must be a valid, /// rooted path on the running host for the same reason the auth DB path must be (SEC-33): a /// non-rooted value silently resolves against the launch working directory. /// public sealed class GalaxyRepositoryOptionsValidator : OptionsValidatorBase { // See GatewayOptionsValidator for why this is nullable and what null means. private readonly string? _contentRootPath; /// /// Initializes a new instance of the class for /// the dependency-injection path, taking the content root from the host environment. /// /// The host environment. public GalaxyRepositoryOptionsValidator(IHostEnvironment environment) { ArgumentNullException.ThrowIfNull(environment); _contentRootPath = environment.ContentRootPath; } /// /// Initializes a new instance of the class for /// unit tests and non-DI callers. /// /// /// Content root to test the snapshot path against; leaves the /// content-root rule inactive. /// internal GalaxyRepositoryOptionsValidator(string? contentRootPath = null) { _contentRootPath = contentRootPath; } /// protected override void Validate(ValidationBuilder builder, GalaxyRepositoryOptions options) { if (!options.PersistSnapshot) { // Persistence disabled: the snapshot path is never used, so nothing to validate. return; } if (string.IsNullOrWhiteSpace(options.SnapshotCachePath)) { builder.Add( "MxGateway:Galaxy:SnapshotCachePath is required when MxGateway:Galaxy:PersistSnapshot is true."); return; } GatewayConfigPathRules.AddIfInvalidPath( options.SnapshotCachePath, "MxGateway:Galaxy:SnapshotCachePath must be a valid filesystem path.", builder); GatewayConfigPathRules.AddIfNotRooted( options.SnapshotCachePath, "MxGateway:Galaxy:SnapshotCachePath must be an absolute (rooted) path so the Galaxy snapshot never lands in the launch working directory.", builder); GatewayConfigPathRules.AddIfUnderContentRoot( options.SnapshotCachePath, _contentRootPath, $"MxGateway:Galaxy:SnapshotCachePath must not be inside the application directory ({_contentRootPath}). The upgrade procedure renames that directory, so the cached snapshot is discarded on every deploy and the gateway starts cold.", builder); } }