193daa9ee8
Same-commit docs rule (were missed in the prior commit): - docs/GalaxyRepository.md: SnapshotCachePath now documents the per-OS derived default and the GalaxyRepositoryOptionsValidator rooting/validity enforcement. - A2-galaxyrepository-adoption-handoff.md: correct the now-inaccurate NSSM caveat (SnapshotCachePath override is optional, not required; blank seeds a rooted host default, no silent no-op) and repoint the option-validation item at the new GalaxyRepositoryOptionsValidator. SEC-34 guard confirmed and documented: TryParseKeyId's '_' split cannot truncate a key id because both — and the only — gateway key-creation paths (ApiKeyAdminCommandLineParser.IsValidKeyId, DashboardApiKeyManagementService.ValidateKeyId) restrict key ids to IsAsciiLetterOrDigit || '.' || '-', and key ids are never library-generated. Added a citing comment; no behavior change. Test consolidation: moved the three host-start SqlitePath overrides into TestHostEnvironmentInitializer (per-process temp store, mirroring Secrets__SqlitePath) so future host-start tests auto-cover.
103 lines
5.8 KiB
C#
103 lines
5.8 KiB
C#
using System.Runtime.CompilerServices;
|
|
using System.Security.Cryptography;
|
|
|
|
namespace ZB.MOM.WW.MxGateway.Tests.TestSupport;
|
|
|
|
/// <summary>
|
|
/// Defaults the host environment to Development and isolates the test process's on-disk
|
|
/// gateway paths, for the whole test assembly.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Many tests build the full gateway host through <c>GatewayApplication.Build</c> against the dev
|
|
/// <c>appsettings.json</c> (which ships <c>Ldap:Transport=None</c> and other dev-only defaults).
|
|
/// An unset environment resolves to Production, where the production guards fail startup
|
|
/// by design — so those host-building tests would trip the guards. Setting the environment to
|
|
/// Development once, before any test runs, keeps that suite exercising app wiring rather than
|
|
/// production-config validation. Tests that specifically assert production behavior construct
|
|
/// <c>GatewayOptionsValidator</c> with its <c>isProduction</c> constructor (no host environment) and
|
|
/// are unaffected; a test that needs Production can still pass <c>--environment=Production</c>, which
|
|
/// overrides this default.
|
|
/// <para>
|
|
/// The self-signed-cert path is also defaulted to a per-process temp file. Otherwise every
|
|
/// full-host test that triggers HTTPS-cert generation writes the shared
|
|
/// <c>CommonApplicationData/MxGateway/certs/gateway-selfsigned.pfx</c> default — parallel xUnit
|
|
/// test classes then collide on that path's temp file (Windows: "the process cannot access the
|
|
/// file ... because it is being used by another process"), and on a shared CI/dev box the suite
|
|
/// also fights the deployed gateway service for the same file. Pointing at a per-process path
|
|
/// isolates the suite: the first host-building test generates the cert, the rest load it.
|
|
/// </para>
|
|
/// </remarks>
|
|
internal static class TestHostEnvironmentInitializer
|
|
{
|
|
/// <summary>
|
|
/// Applies the Development environment and isolated self-signed-cert path defaults described
|
|
/// on this type, run once by the runtime before any test in the assembly executes.
|
|
/// </summary>
|
|
[ModuleInitializer]
|
|
internal static void SetDevelopmentEnvironmentDefault()
|
|
{
|
|
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")))
|
|
{
|
|
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MxGateway__Tls__SelfSignedCertPath")))
|
|
{
|
|
// ProcessId keeps the path stable within this test process (so a valid cert
|
|
// generated by the first host-building test is reused by the rest) yet unique
|
|
// across processes (so concurrent test runs / the deployed service never share it).
|
|
string certPath = Path.Combine(
|
|
Path.GetTempPath(),
|
|
$"mxgw-tests-{Environment.ProcessId}",
|
|
"gateway-selfsigned.pfx");
|
|
Environment.SetEnvironmentVariable("MxGateway__Tls__SelfSignedCertPath", certPath);
|
|
}
|
|
|
|
// Host-building tests must not depend on a seeded secret store. The shipped appsettings.json
|
|
// sources the LDAP bind password from ${secret:ldap/mxgateway/bind}, which the pre-host
|
|
// expander in GatewayApplication.CreateBuilder resolves before the host is built; with no
|
|
// seeded store (as on CI) that resolution fails closed with SecretNotFoundException. Supplying
|
|
// the bind password as an environment override — the same supported way an operator can — makes
|
|
// config["MxGateway:Ldap:ServiceAccountPassword"] a plain literal (the env provider outranks the
|
|
// JSON provider), so the expander sees no ${secret:} prefix and skips it. No store/seed needed.
|
|
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MxGateway__Ldap__ServiceAccountPassword")))
|
|
{
|
|
Environment.SetEnvironmentVariable("MxGateway__Ldap__ServiceAccountPassword", "test-bind-password");
|
|
}
|
|
|
|
// The runtime AddZbSecrets registration still runs SqliteSecretsStoreMigrator.MigrateAsync on
|
|
// startup, which needs a valid master key and a writable store path. Point the store at a
|
|
// per-process temp file (not the test working dir) and supply a throwaway base64 32-byte key so
|
|
// migration succeeds without touching any real/shared secrets store.
|
|
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ZB_SECRETS_MASTER_KEY")))
|
|
{
|
|
Environment.SetEnvironmentVariable(
|
|
"ZB_SECRETS_MASTER_KEY",
|
|
Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)));
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("Secrets__SqlitePath")))
|
|
{
|
|
string secretsPath = Path.Combine(
|
|
Path.GetTempPath(),
|
|
$"mxgw-tests-{Environment.ProcessId}",
|
|
"secrets.db");
|
|
Environment.SetEnvironmentVariable("Secrets__SqlitePath", secretsPath);
|
|
}
|
|
|
|
// Starting the full host eagerly opens the auth SQLite store. Since SEC-33 the shipped
|
|
// appsettings.json no longer carries an Authentication:SqlitePath, and the CommonApplicationData
|
|
// code default resolves under an unwritable /usr/share on macOS. Point every host-building test at
|
|
// a per-process temp store (same pattern as Secrets__SqlitePath above) so host-start tests are
|
|
// auto-covered without a per-test override; a test that needs its own store still overrides this.
|
|
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MxGateway__Authentication__SqlitePath")))
|
|
{
|
|
string authPath = Path.Combine(
|
|
Path.GetTempPath(),
|
|
$"mxgw-tests-{Environment.ProcessId}",
|
|
"gateway-auth.db");
|
|
Environment.SetEnvironmentVariable("MxGateway__Authentication__SqlitePath", authPath);
|
|
}
|
|
}
|
|
}
|