using System.Xml.Linq; namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests; public sealed class LegacyRuntimeAssetDeploymentContractTests { private static readonly string RepositoryRoot = FindRepositoryRoot(); private static readonly string ProjectPath = Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "MBN_STOCK_WEBVIEW.LegacyParityApp.csproj"); [Fact] public void LegacyParityProjectLinksCutsAndResIntoOutputPublishAndMsix() { var project = XDocument.Load(ProjectPath); var contents = project.Descendants("Content").ToArray(); AssertLinkedRuntimeTree(contents, "$(LegacyCutsSourceRoot)\\**\\*", "Cuts\\"); AssertLinkedRuntimeTree(contents, "@(LegacyPackagedResAsset)", "Res\\"); var packagedResNames = project.Descendants("LegacyPackagedResAsset") .Select(element => Path.GetFileName(element.Attribute("Include")?.Value)) .ToHashSet(StringComparer.OrdinalIgnoreCase); string[] requiredUiMenus = [ "setup.ini", "기타.ini", "업종.ini", "업종_코스닥.ini", "업종_코스피.ini", "종목.ini", "종목_0111.ini", "종목비교.ini", "지수.ini", "지수_0318.ini", "지수_250401.ini", "해외.ini", "환율.ini" ]; Assert.Equal(34, packagedResNames.Count); Assert.All(requiredUiMenus, name => Assert.Contains(name, packagedResNames)); Assert.DoesNotContain("MmoneyCoder.ini", packagedResNames); Assert.DoesNotContain("MmoneyCoder - 복사본.ini", packagedResNames); Assert.DoesNotContain("MmoneyCoder.ini.bak", packagedResNames); Assert.DoesNotContain("MmoneyCoder.zip", packagedResNames); Assert.DoesNotContain("afiedt.buf.txt", packagedResNames); } [Fact] public void GraphEPreviewsExposeOnlyFourAllowlistedBitmapsThroughTheTrustedWebRoot() { var project = XDocument.Load(ProjectPath); var previewNames = project.Descendants("LegacyFinancialPreviewAsset") .Select(element => Path.GetFileName(element.Attribute("Include")?.Value)!) .ToHashSet(StringComparer.OrdinalIgnoreCase); Assert.Equal( new HashSet( ["pie.bmp", "Grow.bmp", "sell.bmp", "profit.bmp"], StringComparer.OrdinalIgnoreCase), previewNames); var previewContent = Assert.Single( project.Descendants("Content"), element => string.Equals( element.Attribute("Include")?.Value, "@(LegacyFinancialPreviewAsset)", StringComparison.Ordinal)); Assert.Equal( "Web\\Previews\\%(Filename)%(Extension)", previewContent.Element("Link")?.Value); Assert.Equal( "Web\\Previews\\%(Filename)%(Extension)", previewContent.Element("TargetPath")?.Value); Assert.Equal( "PreserveNewest", previewContent.Element("CopyToOutputDirectory")?.Value); Assert.Equal( "PreserveNewest", previewContent.Element("CopyToPublishDirectory")?.Value); Assert.DoesNotContain( project.Descendants("Content"), element => string.Equals( element.Attribute("Include")?.Value, "$(LegacyResSourceRoot)\\**\\*", StringComparison.OrdinalIgnoreCase)); var window = File.ReadAllText(Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "MainWindow.xaml.cs")); Assert.Equal( 1, window.Split( "SetVirtualHostNameToFolderMapping(", StringSplitOptions.None).Length - 1); Assert.Contains("LegacyBridgeProtocol.TrustedHost", window, StringComparison.Ordinal); Assert.Contains("webRoot", window, StringComparison.Ordinal); Assert.DoesNotContain( "SetVirtualHostNameToFolderMapping(\"res", window, StringComparison.OrdinalIgnoreCase); } [Fact] public void CustomerWordmarkIsProjectedFromTheAllowlistedLegacyAssetIntoTheTrustedWebRoot() { var project = XDocument.Load(ProjectPath); var brandAsset = Assert.Single(project.Descendants("LegacyBrandAsset")); Assert.Equal( "$(LegacyResSourceRoot)\\logo.png", brandAsset.Attribute("Include")?.Value); var brandContent = Assert.Single( project.Descendants("Content"), element => string.Equals( element.Attribute("Include")?.Value, "@(LegacyBrandAsset)", StringComparison.Ordinal)); Assert.Equal( "Web\\Brand\\%(Filename)%(Extension)", brandContent.Element("Link")?.Value); Assert.Equal( "Web\\Brand\\%(Filename)%(Extension)", brandContent.Element("TargetPath")?.Value); Assert.Equal( "PreserveNewest", brandContent.Element("CopyToOutputDirectory")?.Value); Assert.Equal( "PreserveNewest", brandContent.Element("CopyToPublishDirectory")?.Value); var packagedResNames = project.Descendants("LegacyPackagedResAsset") .Select(element => Path.GetFileName(element.Attribute("Include")?.Value)) .ToHashSet(StringComparer.OrdinalIgnoreCase); Assert.Contains("logo.png", packagedResNames); } [Fact] public void WebViewIgnoresItsPersistentCacheBeforeExactTrustedNavigation() { var window = File.ReadAllText(Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "MainWindow.xaml.cs")); var mapping = window.IndexOf( "SetVirtualHostNameToFolderMapping(", StringComparison.Ordinal); var disableCache = window.IndexOf( "\"Network.setCacheDisabled\"", StringComparison.Ordinal); var navigation = window.IndexOf( "Browser.Source = new Uri(", StringComparison.Ordinal); Assert.True(mapping >= 0); Assert.True(disableCache > mapping); Assert.True(navigation > disableCache); Assert.Contains( "CoreWebView2HostResourceAccessKind.DenyCors", window, StringComparison.Ordinal); Assert.Equal( 1, window.Split( "\"Network.setCacheDisabled\"", StringSplitOptions.None).Length - 1); Assert.Contains( "\"{\\\"cacheDisabled\\\":true}\"", window, StringComparison.Ordinal); Assert.Contains( "$\"https://{LegacyBridgeProtocol.TrustedHost}/index.html\"", window, StringComparison.Ordinal); Assert.DoesNotContain( "$\"https://{LegacyBridgeProtocol.TrustedHost}/index.html?", window, StringComparison.Ordinal); } [Fact] public void DatabaseCredentialsStayInUserLocalConfigurationAndNeverEnterBuildOutputs() { var project = XDocument.Load(ProjectPath); Assert.DoesNotContain( project.Descendants().Where(element => element.Name.LocalName is "Content" or "None"), element => (element.Attribute("Include")?.Value ?? string.Empty) .Contains("MmoneyCoder.ini", StringComparison.OrdinalIgnoreCase)); Assert.DoesNotContain( project.Descendants("UpToDateCheckInput"), element => (element.Attribute("Include")?.Value ?? string.Empty) .Contains("MmoneyCoder.ini", StringComparison.OrdinalIgnoreCase)); Assert.DoesNotContain( project.Descendants("UpToDateCheckBuilt"), element => (element.Attribute("Include")?.Value ?? string.Empty) .Contains("MmoneyCoder.ini", StringComparison.OrdinalIgnoreCase)); Assert.DoesNotContain( project.Descendants("Target"), element => string.Equals( element.Attribute("Name")?.Value, "CopyLegacyDatabaseIniToLocalOutput", StringComparison.Ordinal)); Assert.DoesNotContain( project.Descendants("Target"), element => string.Equals( element.Attribute("Name")?.Value, "RemoveLegacyDatabaseIniFromLocalOutput", StringComparison.Ordinal)); var scrubTarget = Assert.Single( project.Descendants("Target"), element => string.Equals( element.Attribute("Name")?.Value, "ScrubLegacyDatabaseIniFromBuildOutput", StringComparison.Ordinal)); Assert.Equal("PrepareForBuild", scrubTarget.Attribute("BeforeTargets")?.Value); var scrubDelete = Assert.Single(scrubTarget.Elements("Delete")); Assert.Equal( "$(TargetDir)Res\\MmoneyCoder.ini", scrubDelete.Attribute("Files")?.Value); var validationTarget = Assert.Single( project.Descendants("Target"), element => string.Equals( element.Attribute("Name")?.Value, "ValidateLegacyRuntimeAssets", StringComparison.Ordinal)); Assert.DoesNotContain( validationTarget.Elements("Error"), element => (element.Attribute("Condition")?.Value ?? string.Empty) .Contains("MmoneyCoder.ini", StringComparison.OrdinalIgnoreCase)); var rejectionTarget = Assert.Single( project.Descendants("Target"), element => string.Equals( element.Attribute("Name")?.Value, "RejectLegacyDatabaseIniFromPackagePayload", StringComparison.Ordinal)); Assert.Equal( "_ComputeAppxPackagePayload", rejectionTarget.Attribute("BeforeTargets")?.Value); var forbiddenPayload = Assert.Single( rejectionTarget.Descendants("_ForbiddenLegacyDatabasePackagePayload")); Assert.Contains( "%(PackagingOutputs.Filename)%(PackagingOutputs.Extension)", forbiddenPayload.Attribute("Condition")?.Value, StringComparison.Ordinal); Assert.Single(rejectionTarget.Elements("Error")); } [Fact] public void FreshCloneUsesIsolatedSourceOnlyOutputWithoutWeakeningFullBuilds() { var project = XDocument.Load(ProjectPath); var sourceRootWasSpecified = Assert.Single( project.Descendants("LegacyRuntimeSourceRootWasSpecified")); Assert.Equal( "'$(LegacyRuntimeSourceRoot)' != ''", sourceRootWasSpecified.Attribute("Condition")?.Value); var modes = project.Descendants("LegacyRuntimeAssetsMode").ToArray(); Assert.Equal(2, modes.Length); var requiredMode = Assert.Single( modes, mode => string.Equals(mode.Value, "Required", StringComparison.Ordinal)); var requiredCondition = requiredMode.Attribute("Condition")?.Value; Assert.Contains( "$(LegacyRuntimeSourceRootWasSpecified)", requiredCondition, StringComparison.Ordinal); Assert.Contains( "'$(Configuration)' == 'Release'", requiredCondition, StringComparison.Ordinal); Assert.Contains( "$(GenerateAppxPackageOnBuild)", requiredCondition, StringComparison.Ordinal); Assert.Contains("$(PublishAppxPackage)", requiredCondition, StringComparison.Ordinal); var autoMode = Assert.Single( modes, mode => string.Equals(mode.Value, "Auto", StringComparison.Ordinal)); Assert.Equal( "'$(LegacyRuntimeAssetsMode)' == ''", autoMode.Attribute("Condition")?.Value); var assetsEnabled = Assert.Single( project.Descendants("LegacyRuntimeAssetsEnabled"), element => (element.Attribute("Condition")?.Value ?? string.Empty) .Contains("Exists('$(LegacyRuntimeSourceRoot)')", StringComparison.Ordinal)); Assert.Equal("true", assetsEnabled.Value); var sourceOnlyOutput = Assert.Single(project.Descendants("BaseOutputPath")); Assert.Equal(@"bin\SourceOnly\", sourceOnlyOutput.Value); Assert.Contains( "$(LegacyRuntimeAssetsEnabled)", sourceOnlyOutput.Attribute("Condition")?.Value, StringComparison.Ordinal); var sourceOnlyIntermediate = Assert.Single( project.Descendants("IntermediateOutputPath")); Assert.Equal( @"obj\SourceOnly\$(Platform)\$(Configuration)\", sourceOnlyIntermediate.Value); Assert.Contains( "$(LegacyRuntimeAssetsEnabled)", sourceOnlyIntermediate.Attribute("Condition")?.Value, StringComparison.Ordinal); var sourceOnlyConstants = Assert.Single(project.Descendants("DefineConstants")); Assert.Contains( "SOURCE_ONLY_RUNTIME", sourceOnlyConstants.Value, StringComparison.Ordinal); Assert.Contains( "$(LegacyRuntimeAssetsEnabled)", sourceOnlyConstants.Attribute("Condition")?.Value, StringComparison.Ordinal); var validationTarget = Assert.Single( project.Descendants("Target"), element => string.Equals( element.Attribute("Name")?.Value, "ValidateLegacyRuntimeAssets", StringComparison.Ordinal)); var sourceOnlyMessage = Assert.Single( validationTarget.Elements("Message"), message => (message.Attribute("Condition")?.Value ?? string.Empty) .Contains("$(LegacyRuntimeAssetsMode)", StringComparison.Ordinal)); Assert.Contains( "$(LegacyRuntimeAssetsMode)", sourceOnlyMessage.Attribute("Condition")?.Value, StringComparison.Ordinal); Assert.Contains( "safe first-run setup app", sourceOnlyMessage.Attribute("Text")?.Value, StringComparison.Ordinal); Assert.Contains( "select the existing Cuts and Res folders", sourceOnlyMessage.Attribute("Text")?.Value, StringComparison.Ordinal); var fullRuntimeMessage = Assert.Single( validationTarget.Elements("Message"), message => (message.Attribute("Text")?.Value ?? string.Empty) .Contains( "Verified full legacy runtime assets are enabled", StringComparison.Ordinal)); Assert.Contains( "Verified full legacy runtime assets are enabled", fullRuntimeMessage.Attribute("Text")?.Value, StringComparison.Ordinal); var runtimeValidationErrors = validationTarget.Elements("Error") .Where(error => (error.Attribute("Condition")?.Value ?? string.Empty) .Contains("Exists(", StringComparison.Ordinal)) .ToArray(); Assert.NotEmpty(runtimeValidationErrors); Assert.All(runtimeValidationErrors, error => Assert.Contains( "$(LegacyRuntimeAssetsValidationEnabled)", error.Attribute("Condition")?.Value, StringComparison.Ordinal)); Assert.Contains( runtimeValidationErrors, error => (error.Attribute("Text")?.Value ?? string.Empty).Contains( "Initialize-ExistingDevelopmentPc.ps1", StringComparison.Ordinal)); string[] externalContentIncludes = [ @"$(LegacyCutsSourceRoot)\**\*", "@(LegacyPackagedResAsset)", "@(LegacyFinancialPreviewAsset)", "@(LegacyBrandAsset)" ]; Assert.All(externalContentIncludes, include => { var content = Assert.Single( project.Descendants("Content"), element => string.Equals( element.Attribute("Include")?.Value, include, StringComparison.Ordinal)); Assert.Contains( "$(LegacyRuntimeAssetsEnabled)", content.Attribute("Condition")?.Value, StringComparison.Ordinal); }); Assert.DoesNotContain( project.Descendants("Target"), element => string.Equals( element.Attribute("Name")?.Value, "CopyLegacyDatabaseIniToLocalOutput", StringComparison.Ordinal)); var mainWindow = File.ReadAllText(Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "MainWindow.xaml.cs")); Assert.Contains("#if SOURCE_ONLY_RUNTIME", mainWindow, StringComparison.Ordinal); Assert.Contains( "Source-only builds do not initialize a database runtime.", mainWindow, StringComparison.Ordinal); var playout = File.ReadAllText(Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "MainWindow.Playout.cs")); Assert.Contains("forceSafeDryRun: IsSourceOnlyBuild", playout, StringComparison.Ordinal); } [Fact] public void LegacyRuntimeSourceRootIsOverrideableAndValidatedBeforeBuild() { var project = XDocument.Load(ProjectPath); var sourceRoot = Assert.Single( project.Descendants("LegacyRuntimeSourceRoot"), element => element.Attribute("Condition") is not null); Assert.Equal("'$(LegacyRuntimeSourceRoot)' == ''", sourceRoot.Attribute("Condition")!.Value); Assert.Contains(".first-run-runtime-not-configured-0F72B3C8", sourceRoot.Value, StringComparison.Ordinal); var target = Assert.Single( project.Descendants("Target"), element => string.Equals( element.Attribute("Name")?.Value, "ValidateLegacyRuntimeAssets", StringComparison.Ordinal)); Assert.Equal("PrepareForBuild", target.Attribute("BeforeTargets")?.Value); var conditions = target.Elements("Error") .Select(error => error.Attribute("Condition")?.Value) .Where(condition => condition is not null) .ToArray(); string[] requiredSentinels = [ "$(LegacyRuntimeSourceRoot)", "$(LegacyCutsSourceRoot)", "$(LegacyResSourceRoot)", "$(LegacyCutsSourceRoot)\\%(LegacyRequiredScene.Identity).t2s", "$(LegacyCutsSourceRoot)\\%(LegacyRequiredBuiltInAsset.Identity)", "$(LegacyResSourceRoot)\\logo.png", "$(LegacyResSourceRoot)\\종목.ini", "$(LegacyResSourceRoot)\\업종_코스피.ini", "$(LegacyResSourceRoot)\\업종_코스닥.ini", "$(LegacyResSourceRoot)\\해외.ini", "$(LegacyResSourceRoot)\\환율.ini", "$(LegacyResSourceRoot)\\지수.ini" ]; Assert.All(requiredSentinels, sentinel => Assert.Contains(conditions, condition => condition!.Contains(sentinel, StringComparison.Ordinal))); var requiredScenes = Assert.Single(project.Descendants("LegacyRequiredScene")) .Attribute("Include")!.Value .Split(';', StringSplitOptions.RemoveEmptyEntries); Assert.Equal(45, requiredScenes.Length); Assert.Equal(requiredScenes.Length, requiredScenes.Distinct(StringComparer.Ordinal).Count()); Assert.Contains("5001", requiredScenes); Assert.Contains("5076", requiredScenes); Assert.Contains("5079", requiredScenes); Assert.Contains("6001", requiredScenes); var requiredAssets = Assert.Single( project.Descendants("LegacyRequiredBuiltInAsset")) .Attribute("Include")!.Value .Split(';', StringSplitOptions.RemoveEmptyEntries); Assert.Equal(9, requiredAssets.Length); Assert.Contains(@"images\주유기merge.png", requiredAssets); Assert.Contains(@"images\35752913_l.jpg", requiredAssets); Assert.Contains(@"Images\KRX.png", requiredAssets); Assert.Contains(@"Images\NXT.png", requiredAssets); Assert.DoesNotContain( target.Elements("Error"), error => (error.Attribute("Condition")?.Value ?? string.Empty) .Contains("MmoneyCoder.ini", StringComparison.OrdinalIgnoreCase)); } [Fact] public void DevelopmentLiveHandoffUsesAnIgnoredVerifiedRuntimeRootAndSafeLocalFiles() { var directoryPropsPath = Path.Combine(RepositoryRoot, "Directory.Build.props"); var directoryProps = XDocument.Load(directoryPropsPath); var localImport = Assert.Single(directoryProps.Descendants("Import")); Assert.Equal( "$(MSBuildThisFileDirectory)Directory.Build.local.props", localImport.Attribute("Project")?.Value); Assert.Contains( "Exists(", localImport.Attribute("Condition")?.Value, StringComparison.Ordinal); var gitIgnore = File.ReadAllLines(Path.Combine(RepositoryRoot, ".gitignore")); Assert.Contains("Directory.Build.local.props", gitIgnore); var initializer = File.ReadAllText(Path.Combine( RepositoryRoot, "scripts", "Initialize-DevelopmentLiveConfig.ps1")); Assert.Contains( "[ValidateSet('127.0.0.1', '::1')]", initializer, StringComparison.Ordinal); Assert.Contains("mode = 'DryRun'", initializer, StringComparison.Ordinal); Assert.Contains( "trustedLiveOutputEnabled = $true", initializer, StringComparison.Ordinal); Assert.Contains( "maximumReconnectAttempts = 0", initializer, StringComparison.Ordinal); Assert.Contains("reconnectEnabled = $false", initializer, StringComparison.Ordinal); Assert.Contains( "maximumAutomaticRefreshesPerTakeIn = 0", initializer, StringComparison.Ordinal); Assert.Contains( "I_AUTHORIZE_LIVE_PROGRAM_OUTPUT_FOR_THIS_LAUNCH", initializer, StringComparison.Ordinal); Assert.Contains( "SetAccessRuleProtection($true, $false)", initializer, StringComparison.Ordinal); var authorizationInvalidation = initializer.IndexOf( "Invalidate-ExistingAuthorization -Path $authorizationPath", StringComparison.Ordinal); var baseConfigurationWrite = initializer.IndexOf( "Write-ProtectedJson $playoutPath", StringComparison.Ordinal); Assert.True(authorizationInvalidation >= 0); Assert.True(baseConfigurationWrite > authorizationInvalidation); Assert.Contains( "Write-ProtectedJson $authorizationPath", initializer, StringComparison.Ordinal); } [Fact] public void DevelopmentRuntimeBundleRequiresIndependentHashAndClosedPayloadValidation() { var bundleCreator = File.ReadAllText(Path.Combine( RepositoryRoot, "scripts", "New-LegacyRuntimeBundle.ps1")); var bundleInitializer = File.ReadAllText(Path.Combine( RepositoryRoot, "scripts", "Initialize-LegacyRuntimeBundle.ps1")); Assert.Contains("$expectedResAssetCount = 34", bundleCreator, StringComparison.Ordinal); Assert.Contains( "Get-GitRepositoryAncestor -Path $sourceRoot", bundleCreator, StringComparison.Ordinal); Assert.Contains( "MmoneyCoder material is forbidden", bundleCreator, StringComparison.Ordinal); Assert.Contains( "LegacyRuntimeBundle.zip.sha256", bundleCreator, StringComparison.Ordinal); Assert.Contains( "[string] $ExpectedSha256", bundleInitializer, StringComparison.Ordinal); Assert.Contains( "ExpectedSha256 must be a separately delivered", bundleInitializer, StringComparison.Ordinal); var archiveHashValidation = bundleInitializer.IndexOf( "$actualArchiveHash.Equals(", StringComparison.Ordinal); var archiveOpen = bundleInitializer.IndexOf( "New-Object IO.Compression.ZipArchive(", StringComparison.Ordinal); Assert.True(archiveHashValidation >= 0); Assert.True(archiveOpen > archiveHashValidation); Assert.Contains( "Archive entry expanded beyond its declared length", bundleInitializer, StringComparison.Ordinal); Assert.Contains( "$actualCutsFileCount -le 0", bundleInitializer, StringComparison.Ordinal); Assert.Contains( "[Environment+SpecialFolder]::LocalApplicationData", bundleInitializer, StringComparison.Ordinal); Assert.DoesNotContain( "Get-NormalizedFullPath -Path $env:LOCALAPPDATA", bundleInitializer, StringComparison.Ordinal); Assert.Contains( "Existing Directory.Build.local.props is conditional, duplicated", bundleInitializer, StringComparison.Ordinal); Assert.Contains( "Assert-NoReparsePointInTree", bundleInitializer, StringComparison.Ordinal); } [Fact] public void ExistingDevelopmentPcInitializerUsesLocalAssetsWithoutPerformingLiveActions() { var initializer = File.ReadAllText(Path.Combine( RepositoryRoot, "scripts", "Initialize-ExistingDevelopmentPc.ps1")); Assert.Contains("[string] $LegacyRuntimeSourceRoot", initializer, StringComparison.Ordinal); Assert.Contains("[switch] $NoFolderPicker", initializer, StringComparison.Ordinal); Assert.Contains( @"..\MBN_STOCK_N\MBN_STOCK_N\bin\Debug", initializer, StringComparison.Ordinal); Assert.Contains( "Test-DirectCutsAndResRootCandidate", initializer, StringComparison.Ordinal); Assert.Contains( "-Path $siblingCandidate", initializer, StringComparison.Ordinal); Assert.Contains( "System.Windows.Forms.FolderBrowserDialog", initializer, StringComparison.Ordinal); Assert.Contains( "$selectedLeaf.Equals('Cuts'", initializer, StringComparison.Ordinal); Assert.Contains( "$selectedLeaf.Equals('Res'", initializer, StringComparison.Ordinal); Assert.Contains( "single common parent of Cuts and Res", initializer, StringComparison.Ordinal); Assert.Contains( "must be on a ready local fixed drive", initializer, StringComparison.Ordinal); Assert.Contains( "must be outside and must not overlap this repository", initializer, StringComparison.Ordinal); Assert.Contains("Assert-NoReparsePointInTree", initializer, StringComparison.Ordinal); Assert.Contains("'New-LegacyRuntimeBundle.ps1'", initializer, StringComparison.Ordinal); Assert.Contains("'Initialize-LegacyRuntimeBundle.ps1'", initializer, StringComparison.Ordinal); Assert.Contains( "$existingRuntime.ManifestSha256.Equals(", initializer, StringComparison.Ordinal); Assert.Contains( "Assert-InstalledRuntimeMatchesManifest", initializer, StringComparison.Ordinal); Assert.Contains( "Installed runtime bundle contains an unexpected file", initializer, StringComparison.Ordinal); Assert.Contains("[switch] $ReplaceRuntimeBinding", initializer, StringComparison.Ordinal); Assert.Contains("Set-RuntimeBindingAtomically", initializer, StringComparison.Ordinal); Assert.Contains( "[IO.File]::Replace($temporary, $destination, $backup)", initializer, StringComparison.Ordinal); var shadowInstall = initializer.IndexOf( "-RepositoryRoot $shadowRepositoryRoot", StringComparison.Ordinal); var bindingReplace = initializer.IndexOf( "Set-RuntimeBindingAtomically", shadowInstall, StringComparison.Ordinal); Assert.True(shadowInstall >= 0); Assert.True(bindingReplace > shadowInstall); Assert.Contains("[string] $DatabaseIniPath", initializer, StringComparison.Ordinal); Assert.Contains("[IO.Path]::IsPathRooted($DatabaseIniPath)", initializer, StringComparison.Ordinal); Assert.Contains("[switch] $SkipDatabaseProfile", initializer, StringComparison.Ordinal); Assert.Contains("[switch] $ReplaceDatabaseProfile", initializer, StringComparison.Ordinal); Assert.Contains(@"Res\MmoneyCoder.ini", initializer, StringComparison.Ordinal); Assert.Contains("$maximumDatabaseIniLength = 1MB", initializer, StringComparison.Ordinal); Assert.Contains("Copy-DatabaseProfileAtomically", initializer, StringComparison.Ordinal); Assert.Contains( "[IO.File]::Replace($temporaryPath, $Destination, $backupPath)", initializer, StringComparison.Ordinal); Assert.Contains("SetAccessRuleProtection($true, $false)", initializer, StringComparison.Ordinal); Assert.Contains("'Inspect-K3DRegistration.ps1'", initializer, StringComparison.Ordinal); Assert.Contains("Get-VerifiedK3DRegistration -Reports $registrationReports", initializer, StringComparison.Ordinal); Assert.Contains( "[string] $registration.RegistryHive -cne 'HKLM'", initializer, StringComparison.Ordinal); Assert.Contains( "[string] $registration.RegistryView -cne 'Registry64'", initializer, StringComparison.Ordinal); Assert.Contains( "[string] $registration.CurrentUserOverrides -cne 'None'", initializer, StringComparison.Ordinal); Assert.Contains( "[string] $classReport.ThreadingModel -cne 'Apartment'", initializer, StringComparison.Ordinal); Assert.DoesNotContain("Activator.CreateInstance", initializer, StringComparison.Ordinal); Assert.DoesNotContain("Connect(", initializer, StringComparison.Ordinal); Assert.DoesNotContain("TAKE IN", initializer, StringComparison.Ordinal); Assert.DoesNotContain("TAKE OUT", initializer, StringComparison.Ordinal); Assert.Contains("[switch] $ConfigureDevelopmentLive", initializer, StringComparison.Ordinal); Assert.Contains("[switch] $ReplaceLiveConfig", initializer, StringComparison.Ordinal); Assert.Contains( "-ConfigureDevelopmentLive requires the default Debug x64 build verification.", initializer, StringComparison.Ordinal); Assert.Contains( "Independent native and interop SHA-256 approvals are both required.", initializer, StringComparison.Ordinal); Assert.Contains( "Get-FileHash -LiteralPath $nativePath -Algorithm SHA256", initializer, StringComparison.Ordinal); Assert.Contains( "Get-FileHash -LiteralPath $interopPath -Algorithm SHA256", initializer, StringComparison.Ordinal); Assert.Contains( "$PlayoutHost -cne '127.0.0.1'", initializer, StringComparison.Ordinal); Assert.Contains( "Existing Development Live files differ from the exact requested", initializer, StringComparison.Ordinal); Assert.Contains("& $DotNetPath build $ProjectPath", initializer, StringComparison.Ordinal); Assert.Contains( "'-p:LegacyRuntimeAssetsMode=Required'", initializer, StringComparison.Ordinal); Assert.Contains( "$runtimeRootProperty = \"-p:LegacyRuntimeSourceRoot=$ExpectedRuntimeRoot\"", initializer, StringComparison.Ordinal); Assert.Contains( "Get-Command -Name 'dotnet.exe' -CommandType Application", initializer, StringComparison.Ordinal); Assert.Contains( "'-getProperty:LegacyRuntimeAssetsEnabled'", initializer, StringComparison.Ordinal); Assert.Contains( "unexpectedly resolved as SourceOnly", initializer, StringComparison.Ordinal); Assert.Contains("Debug x64 payload count mismatch", initializer, StringComparison.Ordinal); Assert.Contains( "Credential-bearing MmoneyCoder.ini entered the Debug build output.", initializer, StringComparison.Ordinal); var runtimeWrite = initializer.LastIndexOf( "Set-RuntimeBindingAtomically", StringComparison.Ordinal); var pinWrite = initializer.LastIndexOf( "Write-ProtectedUtf8TextAtomically", StringComparison.Ordinal); var databaseWrite = initializer.LastIndexOf( "Copy-DatabaseProfileAtomically", StringComparison.Ordinal); var build = initializer.LastIndexOf( "Invoke-DebugBuildAndVerify", StringComparison.Ordinal); var finalK3dVerification = initializer.LastIndexOf( "$finalNativeHash = (", StringComparison.Ordinal); var liveWrite = initializer.LastIndexOf( "& $liveInitializerPath @liveArguments", StringComparison.Ordinal); var cleanup = initializer.LastIndexOf( "-Path $rollbackRoot", StringComparison.Ordinal); Assert.True(pinWrite >= 0); Assert.True(build > pinWrite); Assert.True(databaseWrite > build); Assert.True(finalK3dVerification > databaseWrite); Assert.True(liveWrite > finalK3dVerification); Assert.True(runtimeWrite > liveWrite); Assert.True(cleanup > runtimeWrite); } [Fact] public void ExistingDevelopmentPcInitializerRollsBackAndReissuesLiveFailClosed() { var initializer = File.ReadAllText(Path.Combine( RepositoryRoot, "scripts", "Initialize-ExistingDevelopmentPc.ps1")); Assert.Contains("function New-FileRollbackSnapshot", initializer, StringComparison.Ordinal); Assert.Contains("function Restore-FileRollbackSnapshot", initializer, StringComparison.Ordinal); Assert.Contains("OriginalBytes = [IO.File]::ReadAllBytes($backupPath)", initializer, StringComparison.Ordinal); Assert.Contains("AccessSddl = $accessSddl", initializer, StringComparison.Ordinal); Assert.Contains( "$Description rollback backup failed its immediate ACL/hash verification.", initializer, StringComparison.Ordinal); Assert.Contains( "Previous database profile backup failed immediate ACL/hash verification.", initializer, StringComparison.Ordinal); Assert.Contains( "$Description rollback did not restore the exact bytes and ACL.", initializer, StringComparison.Ordinal); Assert.Contains( "'Local\\MBN_STOCK_WEBVIEW.ExistingDevelopmentPcInitialization.v1'", initializer, StringComparison.Ordinal); Assert.Contains( "Another existing-development-PC initialization is already running.", initializer, StringComparison.Ordinal); Assert.Contains( "Development Live base configuration rollback failed:", initializer, StringComparison.Ordinal); Assert.Contains( "The durable pin remains at", initializer, StringComparison.Ordinal); Assert.Contains( "anchor could not be restored:", initializer, StringComparison.Ordinal); Assert.Contains( "Set-UserOnlyDirectoryAcl -Path $rollbackRoot", initializer, StringComparison.Ordinal); var databaseMutation = initializer.LastIndexOf( "$databaseMutationStarted = $true", StringComparison.Ordinal); var databaseWrite = initializer.LastIndexOf( "Copy-DatabaseProfileAtomically", StringComparison.Ordinal); var databaseRollback = initializer.LastIndexOf( "-Snapshot $databaseSnapshot", StringComparison.Ordinal); var runtimeMutation = initializer.LastIndexOf( "$runtimeBindingMutationStarted = $true", StringComparison.Ordinal); var runtimeWrite = initializer.LastIndexOf( "Set-RuntimeBindingAtomically", StringComparison.Ordinal); var runtimeRollback = initializer.LastIndexOf( "-Snapshot $propsSnapshot", StringComparison.Ordinal); Assert.True(databaseMutation >= 0 && databaseMutation < databaseWrite); Assert.True(runtimeMutation >= 0 && runtimeMutation < runtimeWrite); Assert.True(databaseRollback > databaseWrite); Assert.True(runtimeRollback > runtimeWrite); Assert.Contains("Original failure:", initializer, StringComparison.Ordinal); Assert.Contains("Secondary recovery failure(s):", initializer, StringComparison.Ordinal); Assert.Contains("function Assert-ExactObjectProperties", initializer, StringComparison.Ordinal); Assert.Contains( "-Description 'Runtime bundle creation result'", initializer, StringComparison.Ordinal); Assert.Contains( "-Description 'Runtime bundle initialization result'", initializer, StringComparison.Ordinal); Assert.Contains( "-Description 'K3D registration inspection result'", initializer, StringComparison.Ordinal); Assert.Contains( "Runtime bundle creation result paths escaped or changed the exact output contract.", initializer, StringComparison.Ordinal); Assert.Contains( "Runtime bundle initialization result paths or hashes violate containment.", initializer, StringComparison.Ordinal); Assert.Contains("function Get-VerifiedRuntimeManifest", initializer, StringComparison.Ordinal); Assert.Contains( "duplicate/extra/case/type/format changes are rejected.", initializer, StringComparison.Ordinal); Assert.Contains( "function Assert-DebugRuntimePayloadMatchesManifest", initializer, StringComparison.Ordinal); Assert.Contains( "Debug x64 runtime payload differs from the manifest:", initializer, StringComparison.Ordinal); Assert.Contains( "Debug x64 runtime output contains an unexpected file:", initializer, StringComparison.Ordinal); Assert.Contains( "Debug x64 runtime output does not match the exact manifest file set.", initializer, StringComparison.Ordinal); Assert.Contains( "-Root $targetRoot", initializer, StringComparison.Ordinal); Assert.Contains("function Test-ExactUtf8Text", initializer, StringComparison.Ordinal); Assert.Contains( "case changes, type coercion, reordered properties", initializer, StringComparison.Ordinal); Assert.DoesNotContain("Get-JsonContractText", initializer, StringComparison.Ordinal); var livePreflightStart = initializer.IndexOf( "function Get-DevelopmentLivePreflight", StringComparison.Ordinal); var livePreflightEnd = initializer.IndexOf( "function Copy-DatabaseProfileAtomically", livePreflightStart, StringComparison.Ordinal); Assert.True(livePreflightStart >= 0 && livePreflightEnd > livePreflightStart); var livePreflightFunction = initializer[livePreflightStart..livePreflightEnd]; Assert.DoesNotContain("NeedsWrite = $false", livePreflightFunction, StringComparison.Ordinal); Assert.Contains("DevelopmentLiveReused = $false", initializer, StringComparison.Ordinal); var firstPersistentLiveInvalidation = initializer.IndexOf( "# Invalidate the previous one-launch authorization before database/runtime", StringComparison.Ordinal); var setupDirectoryCreation = initializer.IndexOf( "[IO.Directory]::CreateDirectory($setupParent)", StringComparison.Ordinal); var buildVerification = initializer.LastIndexOf( "Invoke-DebugBuildAndVerify", StringComparison.Ordinal); var pinIssue = initializer.LastIndexOf( "Write-ProtectedUtf8TextAtomically", StringComparison.Ordinal); var finalK3dVerification = initializer.LastIndexOf( "$finalNativeHash = (", StringComparison.Ordinal); var liveIssue = initializer.LastIndexOf( "$liveResults = @(& $liveInitializerPath @liveArguments)", StringComparison.Ordinal); var liveJsonVerification = initializer.LastIndexOf( "-ExpectedJson ([string] $livePreflight.AuthorizationJson)", StringComparison.Ordinal); var bindingCommit = initializer.LastIndexOf( "Set-RuntimeBindingAtomically", StringComparison.Ordinal); var setupCleanup = initializer.LastIndexOf( "-Path $rollbackRoot", StringComparison.Ordinal); var failClosedLiveRemoval = initializer.LastIndexOf( "Remove-DevelopmentLiveAuthorizationFailClosed", StringComparison.Ordinal); Assert.True(pinIssue >= 0); Assert.True(pinIssue < firstPersistentLiveInvalidation); Assert.True(firstPersistentLiveInvalidation < setupDirectoryCreation); Assert.True(setupDirectoryCreation < buildVerification); Assert.True(buildVerification < finalK3dVerification); Assert.True(finalK3dVerification < liveIssue); Assert.True(liveIssue < liveJsonVerification); Assert.True(liveJsonVerification < bindingCommit); Assert.True(bindingCommit < setupCleanup); Assert.True(liveJsonVerification < failClosedLiveRemoval); Assert.Contains( "Development Live initializer returned unexpected success-stream output.", initializer, StringComparison.Ordinal); Assert.Contains( "$Description failed its exact JSON/ACL verification.", initializer, StringComparison.Ordinal); } [Fact] public void RepositoryDoesNotContainCopiedLegacyRuntimeTrees() { Assert.False(Directory.Exists(Path.Combine(RepositoryRoot, "Cuts"))); Assert.False(Directory.Exists(Path.Combine(RepositoryRoot, "Res"))); Assert.False(Directory.Exists(Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "Cuts"))); Assert.False(Directory.Exists(Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "Res"))); } private static void AssertLinkedRuntimeTree( IReadOnlyCollection contents, string include, string targetPrefix) { var content = Assert.Single( contents, element => string.Equals( element.Attribute("Include")?.Value, include, StringComparison.Ordinal)); Assert.StartsWith(targetPrefix, content.Element("Link")?.Value, StringComparison.Ordinal); Assert.StartsWith( targetPrefix, content.Element("TargetPath")?.Value, StringComparison.Ordinal); Assert.Equal("PreserveNewest", content.Element("CopyToOutputDirectory")?.Value); Assert.Equal("PreserveNewest", content.Element("CopyToPublishDirectory")?.Value); } private static string FindRepositoryRoot() { var current = new DirectoryInfo(AppContext.BaseDirectory); while (current is not null) { if (File.Exists(Path.Combine(current.FullName, "MBN_STOCK_WEBVIEW.sln"))) { return current.FullName; } current = current.Parent; } throw new DirectoryNotFoundException("Could not locate the repository root."); } }