feat: resolve typed legacy probe overlays
This commit is contained in:
@@ -4,7 +4,7 @@ using Launcher.Next.Core;
|
|||||||
|
|
||||||
namespace Launcher.Next.Application;
|
namespace Launcher.Next.Application;
|
||||||
|
|
||||||
public sealed record LegacyConfigurationProbeRequest(ResolvedLegacySettingsPath Settings, ResolvedLegacyDownloadListPath DownloadList, ResolvedLegacyProbeEvidenceRoot EvidenceRoot, string PatternName, LegacyCompatibilityOverlay Overlay, string OperationId);
|
public sealed record LegacyConfigurationProbeRequest(ResolvedLegacySettingsPath Settings, ResolvedLegacyDownloadListPath DownloadList, ResolvedLegacyCompatibilityOverlayPath Overlay, ResolvedLegacyProbeEvidenceRoot EvidenceRoot, string PatternName, string OperationId);
|
||||||
public sealed record LegacyConfigurationProbeResult(string TerminalState, IReadOnlyList<PackageRequirement> Requirements, string EvidencePath, IReadOnlyList<string> Diagnostics);
|
public sealed record LegacyConfigurationProbeResult(string TerminalState, IReadOnlyList<PackageRequirement> Requirements, string EvidencePath, IReadOnlyList<string> Diagnostics);
|
||||||
|
|
||||||
/// <summary>Read-only configuration inspection. It intentionally has no package,
|
/// <summary>Read-only configuration inspection. It intentionally has no package,
|
||||||
@@ -15,18 +15,20 @@ public sealed class LegacyConfigurationProbe(LegacyConfigurationAdapter adapter)
|
|||||||
{
|
{
|
||||||
var settingsPath = request.Settings.Value;
|
var settingsPath = request.Settings.Value;
|
||||||
var selectionPath = request.DownloadList.Value;
|
var selectionPath = request.DownloadList.Value;
|
||||||
|
var overlayPath = request.Overlay.Value;
|
||||||
var evidenceRoot = request.EvidenceRoot.Value;
|
var evidenceRoot = request.EvidenceRoot.Value;
|
||||||
if (!File.Exists(settingsPath) || !File.Exists(selectionPath)) throw new InvalidOperationException("LEGACY_PROBE_INPUT_PATH_INVALID");
|
if (!File.Exists(settingsPath) || !File.Exists(selectionPath)) throw new InvalidOperationException("LEGACY_PROBE_INPUT_PATH_INVALID");
|
||||||
if (Path.GetDirectoryName(settingsPath)!.Equals(evidenceRoot, StringComparison.OrdinalIgnoreCase) || Path.GetDirectoryName(selectionPath)!.Equals(evidenceRoot, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("PATH_ROLE_COLLISION");
|
if (Path.GetDirectoryName(settingsPath)!.Equals(evidenceRoot, StringComparison.OrdinalIgnoreCase) || Path.GetDirectoryName(selectionPath)!.Equals(evidenceRoot, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("PATH_ROLE_COLLISION");
|
||||||
Directory.CreateDirectory(evidenceRoot);
|
Directory.CreateDirectory(evidenceRoot);
|
||||||
var before = await Snapshot(settingsPath, selectionPath, cancellationToken);
|
var before = await Snapshot(settingsPath, selectionPath, overlayPath, cancellationToken);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var settings = adapter.ParseSettings(await File.ReadAllTextAsync(settingsPath, cancellationToken));
|
var settings = adapter.ParseSettings(await File.ReadAllTextAsync(settingsPath, cancellationToken));
|
||||||
var pattern = settings.Patterns.Where(x => string.Equals(x.Name, request.PatternName, StringComparison.Ordinal)).ToArray();
|
var pattern = settings.Patterns.Where(x => string.Equals(x.Name, request.PatternName, StringComparison.Ordinal)).ToArray();
|
||||||
if (pattern.Length != 1) throw new InvalidOperationException(pattern.Length == 0 ? "LEGACY_PATTERN_NOT_FOUND" : "LEGACY_PATTERN_AMBIGUOUS");
|
if (pattern.Length != 1) throw new InvalidOperationException(pattern.Length == 0 ? "LEGACY_PATTERN_NOT_FOUND" : "LEGACY_PATTERN_AMBIGUOUS");
|
||||||
var requirements = adapter.Join(pattern[0], adapter.ParseDownloadList(await File.ReadAllTextAsync(selectionPath, cancellationToken)), request.Overlay);
|
var overlay = LegacyCompatibilityOverlayParser.Parse(await File.ReadAllTextAsync(overlayPath, cancellationToken));
|
||||||
var after = await Snapshot(settingsPath, selectionPath, cancellationToken);
|
var requirements = adapter.Join(pattern[0], adapter.ParseDownloadList(await File.ReadAllTextAsync(selectionPath, cancellationToken)), overlay);
|
||||||
|
var after = await Snapshot(settingsPath, selectionPath, overlayPath, cancellationToken);
|
||||||
if (!before.SequenceEqual(after)) throw new InvalidOperationException("LEGACY_PROBE_SOURCE_CHANGED_DURING_READ");
|
if (!before.SequenceEqual(after)) throw new InvalidOperationException("LEGACY_PROBE_SOURCE_CHANGED_DURING_READ");
|
||||||
var evidence = new { mode="LegacyConfigurationProbe", operationId=request.OperationId, terminalState="LEGACY_CONFIGURATION_VERIFIED", selectedPattern=pattern[0].Name, selectedIdCount=requirements.Count, sourceWrites=false, payloadCopied=false, stagingCreated=false, activationAttempted=false, autoCadLaunchAttempted=false, dfsWriteAttempted=false, inputSnapshots=before.Select(x=>Convert.ToHexString(SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(x)))) };
|
var evidence = new { mode="LegacyConfigurationProbe", operationId=request.OperationId, terminalState="LEGACY_CONFIGURATION_VERIFIED", selectedPattern=pattern[0].Name, selectedIdCount=requirements.Count, sourceWrites=false, payloadCopied=false, stagingCreated=false, activationAttempted=false, autoCadLaunchAttempted=false, dfsWriteAttempted=false, inputSnapshots=before.Select(x=>Convert.ToHexString(SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(x)))) };
|
||||||
var output=Path.Combine(evidenceRoot, request.OperationId + ".json");
|
var output=Path.Combine(evidenceRoot, request.OperationId + ".json");
|
||||||
@@ -40,6 +42,6 @@ public sealed class LegacyConfigurationProbe(LegacyConfigurationAdapter adapter)
|
|||||||
return new("PILOT_CONFIGURATION_BLOCKED",[],output,[ex.Message]);
|
return new("PILOT_CONFIGURATION_BLOCKED",[],output,[ex.Message]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static async Task<string[]> Snapshot(string a,string b,CancellationToken ct) => [await One(a,ct),await One(b,ct)];
|
private static async Task<string[]> Snapshot(string a,string b,string c,CancellationToken ct) => [await One(a,ct),await One(b,ct),await One(c,ct)];
|
||||||
private static async Task<string> One(string path,CancellationToken ct) { var info=new FileInfo(path); return path+"|"+info.Length+"|"+info.LastWriteTimeUtc.Ticks+"|"+Convert.ToHexString(await SHA256.HashDataAsync(File.OpenRead(path),ct)); }
|
private static async Task<string> One(string path,CancellationToken ct) { var info=new FileInfo(path); return path+"|"+info.Length+"|"+info.LastWriteTimeUtc.Ticks+"|"+Convert.ToHexString(await SHA256.HashDataAsync(File.OpenRead(path),ct)); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public sealed record ResolvedCatalogRoot
|
|||||||
}
|
}
|
||||||
public sealed record ResolvedLegacySettingsPath { internal ResolvedLegacySettingsPath(string value) => Value=value; public string Value { get; } }
|
public sealed record ResolvedLegacySettingsPath { internal ResolvedLegacySettingsPath(string value) => Value=value; public string Value { get; } }
|
||||||
public sealed record ResolvedLegacyDownloadListPath { internal ResolvedLegacyDownloadListPath(string value) => Value=value; public string Value { get; } }
|
public sealed record ResolvedLegacyDownloadListPath { internal ResolvedLegacyDownloadListPath(string value) => Value=value; public string Value { get; } }
|
||||||
|
public sealed record ResolvedLegacyCompatibilityOverlayPath { internal ResolvedLegacyCompatibilityOverlayPath(string value) => Value=value; public string Value { get; } }
|
||||||
public sealed record ResolvedLegacyProbeEvidenceRoot { internal ResolvedLegacyProbeEvidenceRoot(string value) => Value=value; public string Value { get; } }
|
public sealed record ResolvedLegacyProbeEvidenceRoot { internal ResolvedLegacyProbeEvidenceRoot(string value) => Value=value; public string Value { get; } }
|
||||||
|
|
||||||
public interface IPathResolver
|
public interface IPathResolver
|
||||||
@@ -38,6 +39,7 @@ public interface IPathResolver
|
|||||||
ResolvedCatalogRoot ResolveCatalogRoot(LauncherPathVariables variables);
|
ResolvedCatalogRoot ResolveCatalogRoot(LauncherPathVariables variables);
|
||||||
ResolvedLegacySettingsPath ResolveLegacySettingsPath(LauncherPathVariables variables);
|
ResolvedLegacySettingsPath ResolveLegacySettingsPath(LauncherPathVariables variables);
|
||||||
ResolvedLegacyDownloadListPath ResolveLegacyDownloadListPath(LauncherPathVariables variables);
|
ResolvedLegacyDownloadListPath ResolveLegacyDownloadListPath(LauncherPathVariables variables);
|
||||||
|
ResolvedLegacyCompatibilityOverlayPath ResolveLegacyCompatibilityOverlayPath(LauncherPathVariables variables);
|
||||||
ResolvedLegacyProbeEvidenceRoot ResolveLegacyProbeEvidenceRoot(LauncherPathVariables variables);
|
ResolvedLegacyProbeEvidenceRoot ResolveLegacyProbeEvidenceRoot(LauncherPathVariables variables);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +102,7 @@ public sealed class PathResolver(IReadOnlyDictionary<string, string?>? environme
|
|||||||
}
|
}
|
||||||
public ResolvedLegacySettingsPath ResolveLegacySettingsPath(LauncherPathVariables variables) => new(ResolveExistingFile("LegacySettingsPath", variables));
|
public ResolvedLegacySettingsPath ResolveLegacySettingsPath(LauncherPathVariables variables) => new(ResolveExistingFile("LegacySettingsPath", variables));
|
||||||
public ResolvedLegacyDownloadListPath ResolveLegacyDownloadListPath(LauncherPathVariables variables) => new(ResolveExistingFile("LegacyDownloadListPath", variables));
|
public ResolvedLegacyDownloadListPath ResolveLegacyDownloadListPath(LauncherPathVariables variables) => new(ResolveExistingFile("LegacyDownloadListPath", variables));
|
||||||
|
public ResolvedLegacyCompatibilityOverlayPath ResolveLegacyCompatibilityOverlayPath(LauncherPathVariables variables) => new(ResolveExistingFile("LegacyCompatibilityOverlayPath", variables));
|
||||||
public ResolvedLegacyProbeEvidenceRoot ResolveLegacyProbeEvidenceRoot(LauncherPathVariables variables)
|
public ResolvedLegacyProbeEvidenceRoot ResolveLegacyProbeEvidenceRoot(LauncherPathVariables variables)
|
||||||
{
|
{
|
||||||
var value=ResolvePath(Resolve(variables,["LegacyProbeEvidenceRoot"]).Require("LegacyProbeEvidenceRoot"),variables);
|
var value=ResolvePath(Resolve(variables,["LegacyProbeEvidenceRoot"]).Require("LegacyProbeEvidenceRoot"),variables);
|
||||||
|
|||||||
Reference in New Issue
Block a user