feat: make LegacyParityApp playout live-only

This commit is contained in:
2026-07-28 14:52:59 +09:00
parent 11d3849933
commit ea96a08ad5
23 changed files with 456 additions and 270 deletions

View File

@@ -2,6 +2,7 @@ using System.Security;
using System.Text;
using MBN_STOCK_WEBVIEW.Playout.Configuration;
using MBN_STOCK_WEBVIEW.Playout.Diagnostics;
using MBN_STOCK_WEBVIEW.Playout.Safety;
namespace MBN_STOCK_WEBVIEW.Playout.Tests;
@@ -42,12 +43,18 @@ public sealed class DevelopmentLiveLaunchBootstrapTests
}
[Fact]
public void ResolveLaunchArguments_RejectsMissingOrAdditionalProcessArguments()
public void ResolveLaunchArguments_DistinguishesNormalLaunchFromAdditionalArguments()
{
Assert.Null(DevelopmentLiveLaunchBootstrap.ResolveLaunchArguments("", ["app.exe"]));
Assert.Null(DevelopmentLiveLaunchBootstrap.ResolveLaunchArguments(
var additionalArguments = DevelopmentLiveLaunchBootstrap.ResolveLaunchArguments(
"",
["app.exe", DevelopmentLiveLaunchBootstrap.ExactLaunchArgument, "extra"]));
["app.exe", DevelopmentLiveLaunchBootstrap.ExactLaunchArgument, "extra"]);
Assert.NotNull(additionalArguments);
Assert.NotEqual(string.Empty, additionalArguments);
Assert.NotEqual(
DevelopmentLiveLaunchBootstrap.ExactLaunchArgument,
additionalArguments);
}
[Fact]
@@ -65,13 +72,11 @@ public sealed class DevelopmentLiveLaunchBootstrapTests
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData("--development-live ")]
[InlineData(" --development-live")]
[InlineData("--DEVELOPMENT-LIVE")]
[InlineData("--development-live --another-option")]
public void NonExactArgument_SkipsWithoutReadingOrMutating(string? arguments)
public void NonExactArgument_IsRejectedWithoutReadingOrMutating(string? arguments)
{
var platform = FakePlatform.Valid();
@@ -81,37 +86,56 @@ public sealed class DevelopmentLiveLaunchBootstrapTests
"ignored.json",
platform);
Assert.Equal(DevelopmentLiveBootstrapStatus.Skipped, result.Status);
Assert.Equal("development-live-not-requested", result.Code);
Assert.Equal(DevelopmentLiveBootstrapStatus.Rejected, result.Status);
Assert.Equal("development-live-arguments-invalid", result.Code);
Assert.False(result.IsLaunchAllowed);
Assert.True(result.IsRequested);
Assert.Equal(0, platform.ReadCount);
Assert.Empty(platform.Environment);
}
[Fact]
public void ReleaseBuild_SkipsExactArgumentWithoutReadingOrMutating()
[Theory]
[InlineData(true)]
[InlineData(false)]
public void GateALaunch_BypassesOrdinaryAuthorizationWithoutEnvironmentMutation(
bool isDebugBuild)
{
var platform = FakePlatform.Valid();
platform.Environment[
PlayoutLaunchAuthorization.GateACapabilityEnvironmentVariable] =
new string('A', 64);
var originalEnvironment = platform.Environment.ToArray();
var result = DevelopmentLiveLaunchBootstrap.TryApply(
DevelopmentLiveLaunchBootstrap.ExactLaunchArgument,
isDebugBuild: false,
"ignored.json",
null,
isDebugBuild,
"must-not-be-read.json",
platform);
Assert.Equal(DevelopmentLiveBootstrapStatus.Skipped, result.Status);
Assert.Equal("development-live-debug-only", result.Code);
Assert.Equal(DevelopmentLiveBootstrapStatus.GateABypassed, result.Status);
Assert.Equal("development-live-gate-a-bypassed", result.Code);
Assert.True(result.IsLaunchAllowed);
Assert.False(result.IsRequested);
Assert.Equal(0, platform.ReadCount);
Assert.Empty(platform.Environment);
Assert.Equal(originalEnvironment, platform.Environment);
}
[Fact]
public void DebugExactArgumentAndStrictFile_ApplyAllProcessGates()
[Theory]
[InlineData(null, true)]
[InlineData("", true)]
[InlineData("--development-live", true)]
[InlineData(null, false)]
[InlineData("", false)]
[InlineData("--development-live", false)]
public void NormalOrExactLaunchAndStrictFile_ApplyAllProcessGates(
string? arguments,
bool isDebugBuild)
{
var platform = FakePlatform.Valid();
var result = DevelopmentLiveLaunchBootstrap.TryApply(
DevelopmentLiveLaunchBootstrap.ExactLaunchArgument,
isDebugBuild: true,
arguments,
isDebugBuild,
"authorization.json",
platform);
@@ -188,6 +212,25 @@ public sealed class DevelopmentLiveLaunchBootstrapTests
Assert.Empty(platform.Environment);
}
[Fact]
public void InvalidAuthorizationFileRead_IsUnavailableAndDoesNotMutateEnvironment()
{
var platform = FakePlatform.Valid();
platform.ReadException = new InvalidDataException("sensitive authorization bytes");
var result = DevelopmentLiveLaunchBootstrap.TryApply(
null,
isDebugBuild: false,
"sensitive authorization path",
platform);
Assert.Equal(DevelopmentLiveBootstrapStatus.Rejected, result.Status);
Assert.Equal("development-live-authorization-unavailable", result.Code);
Assert.False(result.IsLaunchAllowed);
Assert.DoesNotContain("sensitive", result.Code, StringComparison.OrdinalIgnoreCase);
Assert.Empty(platform.Environment);
}
[Fact]
public void EnvironmentFailure_DisarmsEveryPreviousProcessValue()
{
@@ -196,7 +239,8 @@ public sealed class DevelopmentLiveLaunchBootstrapTests
InstalledK3dInteropMetadata.ApprovedNativeSha256EnvironmentVariable] = "old-native";
platform.Environment[
InstalledK3dInteropMetadata.ApprovedSha256EnvironmentVariable] = "old-interop";
platform.Environment[DevelopmentLiveLaunchBootstrap.ModeEnvironmentVariable] = "DryRun";
platform.Environment[DevelopmentLiveLaunchBootstrap.ModeEnvironmentVariable] =
"stale-mode";
platform.Environment[PlayoutOptionsLoader.LiveAuthorizationEnvironmentVariable] =
"old-authorization";
platform.FailOnceOnSetName = DevelopmentLiveLaunchBootstrap.ModeEnvironmentVariable;