fix(launcher): harden Campaign LA11 gate evidence
This commit is contained in:
parent
134edabed2
commit
accd01a008
16 changed files with 1820 additions and 210 deletions
|
|
@ -295,29 +295,228 @@ public sealed class LauncherSelfUpdateManagerTests : IDisposable
|
|||
Assert.Equal(publicArguments, ordinary.RemainingArguments);
|
||||
|
||||
SelfUpdateStartupResult deferred = await LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
[LauncherSelfUpdateBootstrap.DeferredArgument, .. publicArguments],
|
||||
["--acdream-self-update-deferred-v1", .. publicArguments],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath);
|
||||
Assert.False(deferred.ShouldExit);
|
||||
Assert.Equal(publicArguments, deferred.RemainingArguments);
|
||||
Assert.True(deferred.ShouldExit);
|
||||
Assert.Equal(64, deferred.ExitCode);
|
||||
Assert.Empty(deferred.RemainingArguments);
|
||||
|
||||
_ = await harness.StageAsync();
|
||||
SelfUpdatePlan applied = await harness.Manager.ApplyPendingAsync(harness.Target);
|
||||
SelfUpdateStartupResult confirmation = await LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
[
|
||||
LauncherSelfUpdateBootstrap.ConfirmArgument,
|
||||
applied.TransactionId,
|
||||
.. publicArguments,
|
||||
],
|
||||
SelfUpdateStartupResult confirmation;
|
||||
using (UpdateSessionBarrier.ExclusiveLease helperLease =
|
||||
harness.Manager.Barrier.AcquireExclusive())
|
||||
{
|
||||
confirmation = await LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
[
|
||||
LauncherSelfUpdateBootstrap.ConfirmArgument,
|
||||
applied.TransactionId,
|
||||
.. publicArguments,
|
||||
],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath);
|
||||
}
|
||||
|
||||
Assert.False(confirmation.ShouldExit);
|
||||
Assert.Equal(publicArguments, confirmation.RemainingArguments);
|
||||
Assert.True(File.Exists(harness.Manager.PendingPlanPath));
|
||||
Assert.True(harness.Manager.IsConfirmed(applied.TransactionId));
|
||||
await harness.Manager.CompleteConfirmedAsync(applied.TransactionId, harness.Target);
|
||||
Assert.False(File.Exists(harness.Manager.PendingPlanPath));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ContendedOrdinaryStartupAllowsOnlyNoPlanOrValidatedStagedPlan()
|
||||
{
|
||||
using var harness = new Harness(_root);
|
||||
using (UpdateSessionBarrier.SessionLease session =
|
||||
harness.Manager.Barrier.AcquireSession())
|
||||
{
|
||||
SelfUpdateStartupResult empty = await LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
["ordinary"],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath);
|
||||
Assert.False(empty.ShouldExit);
|
||||
}
|
||||
|
||||
_ = await harness.StageAsync();
|
||||
using (UpdateSessionBarrier.SessionLease session =
|
||||
harness.Manager.Barrier.AcquireSession())
|
||||
{
|
||||
SelfUpdateStartupResult staged = await LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
["ordinary"],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath);
|
||||
Assert.False(staged.ShouldExit);
|
||||
}
|
||||
|
||||
SelfUpdatePlan awaiting = await harness.Manager.ApplyPendingAsync(harness.Target);
|
||||
using (UpdateSessionBarrier.SessionLease session =
|
||||
harness.Manager.Barrier.AcquireSession())
|
||||
{
|
||||
await Assert.ThrowsAsync<LauncherUpdateException>(() =>
|
||||
LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
["ordinary"],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath));
|
||||
}
|
||||
|
||||
SelfUpdatePlan rolledBack = await harness.Manager
|
||||
.RollbackAwaitingConfirmationAsync(harness.Target);
|
||||
using (UpdateSessionBarrier.SessionLease session =
|
||||
harness.Manager.Barrier.AcquireSession())
|
||||
{
|
||||
await Assert.ThrowsAsync<LauncherUpdateException>(() =>
|
||||
LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
["ordinary"],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath));
|
||||
}
|
||||
|
||||
await SetPlanStateAsync(harness.Manager.PendingPlanPath, "applying");
|
||||
using (UpdateSessionBarrier.SessionLease session =
|
||||
harness.Manager.Barrier.AcquireSession())
|
||||
{
|
||||
await Assert.ThrowsAsync<LauncherUpdateException>(() =>
|
||||
LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
["ordinary"],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath));
|
||||
}
|
||||
|
||||
Assert.Equal(SelfUpdatePlanState.AwaitingConfirmation, awaiting.State);
|
||||
Assert.Equal(SelfUpdatePlanState.RolledBack, rolledBack.State);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OrdinaryStartupRecoversApplyingAndFinalizesVerifiedRollback()
|
||||
{
|
||||
using var harness = new Harness(_root);
|
||||
_ = await harness.StageAsync();
|
||||
_ = await harness.Manager.ApplyPendingAsync(harness.Target);
|
||||
await SetPlanStateAsync(harness.Manager.PendingPlanPath, "applying");
|
||||
|
||||
SelfUpdateStartupResult result = await LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
["ordinary"],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath);
|
||||
|
||||
Assert.False(confirmation.ShouldExit);
|
||||
Assert.Equal(publicArguments, confirmation.RemainingArguments);
|
||||
Assert.False(File.Exists(harness.Manager.PendingPlanPath));
|
||||
Assert.False(harness.Manager.IsConfirmed(applied.TransactionId));
|
||||
Assert.False(result.ShouldExit);
|
||||
Assert.Equal(["ordinary"], result.RemainingArguments);
|
||||
Assert.Null(await harness.Manager.LoadPendingAsync());
|
||||
Assert.Equal("old-launcher", await File.ReadAllTextAsync(harness.LauncherPath));
|
||||
Assert.Equal("old-support", await File.ReadAllTextAsync(harness.SupportPath));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InternalPrefixSpoofsCannotCrossPlanStateOrExecutableTrust()
|
||||
{
|
||||
using var harness = new Harness(_root);
|
||||
_ = await harness.StageAsync();
|
||||
SelfUpdatePlan staged = Assert.IsType<SelfUpdatePlan>(
|
||||
await harness.Manager.LoadPendingAsync());
|
||||
|
||||
await Assert.ThrowsAsync<LauncherUpdateException>(() =>
|
||||
LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
[
|
||||
LauncherSelfUpdateBootstrap.HelperArgument,
|
||||
int.MaxValue.ToString(
|
||||
System.Globalization.CultureInfo.InvariantCulture),
|
||||
harness.Target,
|
||||
staged.TransactionId,
|
||||
],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath));
|
||||
await Assert.ThrowsAsync<LauncherUpdateException>(() =>
|
||||
LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
[LauncherSelfUpdateBootstrap.ConfirmArgument, staged.TransactionId],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath));
|
||||
|
||||
SelfUpdatePlan awaiting = await harness.Manager.ApplyPendingAsync(harness.Target);
|
||||
await Assert.ThrowsAsync<LauncherUpdateException>(() =>
|
||||
LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
[LauncherSelfUpdateBootstrap.ConfirmArgument, awaiting.TransactionId],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
Path.Combine(harness.Target, "spoof-launcher")));
|
||||
await Assert.ThrowsAsync<LauncherUpdateException>(() =>
|
||||
LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
[
|
||||
LauncherSelfUpdateBootstrap.HelperArgument,
|
||||
int.MaxValue.ToString(
|
||||
System.Globalization.CultureInfo.InvariantCulture),
|
||||
harness.Target,
|
||||
awaiting.TransactionId,
|
||||
],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath));
|
||||
|
||||
SelfUpdatePlan rolledBack = await harness.Manager
|
||||
.RollbackAwaitingConfirmationAsync(harness.Target);
|
||||
foreach (string prefix in new[]
|
||||
{
|
||||
LauncherSelfUpdateBootstrap.HelperArgument,
|
||||
LauncherSelfUpdateBootstrap.ConfirmArgument,
|
||||
})
|
||||
{
|
||||
string[] arguments = prefix == LauncherSelfUpdateBootstrap.HelperArgument
|
||||
? [prefix, int.MaxValue.ToString(), harness.Target, rolledBack.TransactionId]
|
||||
: [prefix, rolledBack.TransactionId];
|
||||
await Assert.ThrowsAsync<LauncherUpdateException>(() =>
|
||||
LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
arguments,
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath));
|
||||
}
|
||||
|
||||
SelfUpdateStartupResult deferred = await LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
["--acdream-self-update-deferred-v1"],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath);
|
||||
Assert.True(deferred.ShouldExit);
|
||||
Assert.Equal(64, deferred.ExitCode);
|
||||
|
||||
await File.WriteAllTextAsync(harness.Manager.PendingPlanPath, "{ambiguous");
|
||||
await Assert.ThrowsAsync<LauncherUpdateException>(() =>
|
||||
LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
[LauncherSelfUpdateBootstrap.ConfirmArgument, rolledBack.TransactionId],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath));
|
||||
await Assert.ThrowsAsync<LauncherUpdateException>(() =>
|
||||
LauncherSelfUpdateBootstrap.HandleAsync(
|
||||
[
|
||||
LauncherSelfUpdateBootstrap.HelperArgument,
|
||||
int.MaxValue.ToString(),
|
||||
harness.Target,
|
||||
rolledBack.TransactionId,
|
||||
],
|
||||
harness.Manager,
|
||||
harness.Target,
|
||||
harness.LauncherPath));
|
||||
}
|
||||
|
||||
private static async Task SetPlanStateAsync(string path, string state)
|
||||
{
|
||||
JsonObject plan = Assert.IsType<JsonObject>(JsonNode.Parse(
|
||||
await File.ReadAllTextAsync(path)));
|
||||
plan["state"] = state;
|
||||
await File.WriteAllTextAsync(path, plan.ToJsonString());
|
||||
}
|
||||
|
||||
private sealed class Harness : IDisposable
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue