feat: add verified development live handoff
This commit is contained in:
@@ -187,7 +187,7 @@ public sealed class LegacyRuntimeAssetDeploymentContractTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ActiveDatabaseIniIsPostBuildOutputOnlyAndNeverAPackagingItem()
|
||||
public void DatabaseCredentialsStayInUserLocalConfigurationAndNeverEnterBuildOutputs()
|
||||
{
|
||||
var project = XDocument.Load(ProjectPath);
|
||||
Assert.DoesNotContain(
|
||||
@@ -196,59 +196,49 @@ public sealed class LegacyRuntimeAssetDeploymentContractTests
|
||||
element => (element.Attribute("Include")?.Value ?? string.Empty)
|
||||
.Contains("MmoneyCoder.ini", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var upToDateInput = Assert.Single(project.Descendants("UpToDateCheckInput"));
|
||||
Assert.Equal(
|
||||
"$(LegacyResSourceRoot)\\MmoneyCoder.ini",
|
||||
upToDateInput.Attribute("Include")?.Value);
|
||||
var upToDateBuilt = Assert.Single(project.Descendants("UpToDateCheckBuilt"));
|
||||
Assert.Equal(
|
||||
"$(TargetDir)Res\\MmoneyCoder.ini",
|
||||
upToDateBuilt.Attribute("Include")?.Value);
|
||||
|
||||
var copyTarget = Assert.Single(
|
||||
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.Equal("Build", copyTarget.Attribute("AfterTargets")?.Value);
|
||||
Assert.Contains(
|
||||
"GenerateAppxPackageOnBuild",
|
||||
copyTarget.Attribute("Condition")?.Value,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"PublishAppxPackage",
|
||||
copyTarget.Attribute("Condition")?.Value,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Equal(
|
||||
"$(LegacyResSourceRoot)\\MmoneyCoder.ini",
|
||||
copyTarget.Attribute("Inputs")?.Value);
|
||||
Assert.Equal(
|
||||
"$(TargetDir)Res\\MmoneyCoder.ini",
|
||||
copyTarget.Attribute("Outputs")?.Value);
|
||||
var copy = Assert.Single(copyTarget.Elements("Copy"));
|
||||
Assert.Equal(
|
||||
"$(LegacyResSourceRoot)\\MmoneyCoder.ini",
|
||||
copy.Attribute("SourceFiles")?.Value);
|
||||
Assert.Equal(
|
||||
"$(TargetDir)Res\\MmoneyCoder.ini",
|
||||
copy.Attribute("DestinationFiles")?.Value);
|
||||
var fileWrite = Assert.Single(copyTarget.Descendants("FileWrites"));
|
||||
Assert.Equal(
|
||||
"$(TargetDir)Res\\MmoneyCoder.ini",
|
||||
fileWrite.Attribute("Include")?.Value);
|
||||
|
||||
var cleanTarget = Assert.Single(
|
||||
Assert.DoesNotContain(
|
||||
project.Descendants("Target"),
|
||||
element => string.Equals(
|
||||
element.Attribute("Name")?.Value,
|
||||
"RemoveLegacyDatabaseIniFromLocalOutput",
|
||||
StringComparison.Ordinal));
|
||||
Assert.Equal("Clean", cleanTarget.Attribute("BeforeTargets")?.Value);
|
||||
var delete = Assert.Single(cleanTarget.Elements("Delete"));
|
||||
|
||||
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",
|
||||
delete.Attribute("Files")?.Value);
|
||||
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"),
|
||||
@@ -385,16 +375,12 @@ public sealed class LegacyRuntimeAssetDeploymentContractTests
|
||||
StringComparison.Ordinal);
|
||||
});
|
||||
|
||||
var databaseCopy = Assert.Single(
|
||||
Assert.DoesNotContain(
|
||||
project.Descendants("Target"),
|
||||
element => string.Equals(
|
||||
element.Attribute("Name")?.Value,
|
||||
"CopyLegacyDatabaseIniToLocalOutput",
|
||||
StringComparison.Ordinal));
|
||||
Assert.Contains(
|
||||
"$(LegacyRuntimeAssetsEnabled)",
|
||||
databaseCopy.Attribute("Condition")?.Value,
|
||||
StringComparison.Ordinal);
|
||||
|
||||
var mainWindow = File.ReadAllText(Path.Combine(
|
||||
RepositoryRoot,
|
||||
@@ -447,7 +433,6 @@ public sealed class LegacyRuntimeAssetDeploymentContractTests
|
||||
"$(LegacyResSourceRoot)",
|
||||
"$(LegacyCutsSourceRoot)\\%(LegacyRequiredScene.Identity).t2s",
|
||||
"$(LegacyCutsSourceRoot)\\%(LegacyRequiredBuiltInAsset.Identity)",
|
||||
"$(LegacyResSourceRoot)\\MmoneyCoder.ini",
|
||||
"$(LegacyResSourceRoot)\\logo.png",
|
||||
"$(LegacyResSourceRoot)\\종목.ini",
|
||||
"$(LegacyResSourceRoot)\\업종_코스피.ini",
|
||||
@@ -482,17 +467,138 @@ public sealed class LegacyRuntimeAssetDeploymentContractTests
|
||||
Assert.Contains(@"Images\KRX.png", requiredAssets);
|
||||
Assert.Contains(@"Images\NXT.png", requiredAssets);
|
||||
|
||||
var databaseIniError = Assert.Single(
|
||||
Assert.DoesNotContain(
|
||||
target.Elements("Error"),
|
||||
error => (error.Attribute("Condition")?.Value ?? string.Empty)
|
||||
.Contains("$(LegacyResSourceRoot)\\MmoneyCoder.ini", StringComparison.Ordinal));
|
||||
.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(
|
||||
"GenerateAppxPackageOnBuild",
|
||||
databaseIniError.Attribute("Condition")?.Value,
|
||||
"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(
|
||||
"PublishAppxPackage",
|
||||
databaseIniError.Attribute("Condition")?.Value,
|
||||
"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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user