feat: harden package lifecycle content boundaries
This commit is contained in:
@@ -37,6 +37,15 @@ public sealed record ResolvedPackageStagingRoot { internal ResolvedPackageStagin
|
||||
public sealed record ResolvedActivePackageRoot { internal ResolvedActivePackageRoot(string value)=>Value=value; public string Value{get;} }
|
||||
public sealed record ResolvedPackageLifecycleEvidenceRoot { internal ResolvedPackageLifecycleEvidenceRoot(string value)=>Value=value; public string Value{get;} }
|
||||
public sealed record ResolvedPackagePilotRoot { internal ResolvedPackagePilotRoot(string value)=>Value=value; public string Value{get;} }
|
||||
public sealed record ResolvedPackageCatalogRoot { internal ResolvedPackageCatalogRoot(string value)=>Value=value; public string Value{get;} }
|
||||
public sealed record ResolvedImmutablePackagePath { internal ResolvedImmutablePackagePath(string value)=>Value=value; public string Value{get;} }
|
||||
public sealed record ResolvedPackageLifecycleRoots(
|
||||
ResolvedPackagePilotRoot Pilot,
|
||||
ResolvedPackageCatalogRoot Catalog,
|
||||
ResolvedPackageStagingRoot Staging,
|
||||
ResolvedPackageVersionStoreRoot VersionStore,
|
||||
ResolvedActivePackageRoot Active,
|
||||
ResolvedPackageLifecycleEvidenceRoot Evidence);
|
||||
|
||||
public interface IPathResolver
|
||||
{
|
||||
@@ -48,6 +57,7 @@ public interface IPathResolver
|
||||
ResolvedLegacyCompatibilityOverlayPath ResolveLegacyCompatibilityOverlayPath(LauncherPathVariables variables);
|
||||
ResolvedLegacyProbeEvidenceRoot ResolveLegacyProbeEvidenceRoot(LauncherPathVariables variables);
|
||||
ResolvedPackagePilotRoot ResolvePackagePilotRoot(string value);
|
||||
ResolvedPackageLifecycleRoots ResolvePackageLifecycleRoots(string value);
|
||||
}
|
||||
|
||||
public sealed class PathResolver(IReadOnlyDictionary<string, string?>? environment = null) : IPathResolver
|
||||
@@ -117,7 +127,15 @@ public sealed class PathResolver(IReadOnlyDictionary<string, string?>? environme
|
||||
return new(value);
|
||||
}
|
||||
public ResolvedPackagePilotRoot ResolvePackagePilotRoot(string value)
|
||||
{ if (string.IsNullOrWhiteSpace(value)||value.Contains('*')||value.Contains('?')||value.StartsWith(@"\\")||!Path.IsPathFullyQualified(value)) throw new InvalidOperationException("PACKAGE_PILOT_ROOT_NOT_LOCAL"); var full=Path.GetFullPath(value); var info=new DirectoryInfo(full); if(info.Exists&&info.Attributes.HasFlag(FileAttributes.ReparsePoint)) throw new InvalidOperationException("PACKAGE_ROOT_REPARSE_REJECTED"); return new(full); }
|
||||
{ if (string.IsNullOrWhiteSpace(value)||Uri.IsWellFormedUriString(value,UriKind.Absolute)||value.Contains('*')||value.Contains('?')||value.StartsWith(@"\\")||!Path.IsPathFullyQualified(value)) throw new InvalidOperationException("PACKAGE_PILOT_ROOT_NOT_LOCAL"); var full=Path.GetFullPath(value); var info=new DirectoryInfo(full); if(info.Exists&&info.Attributes.HasFlag(FileAttributes.ReparsePoint)) throw new InvalidOperationException("PACKAGE_ROOT_REPARSE_REJECTED"); return new(full); }
|
||||
public ResolvedPackageLifecycleRoots ResolvePackageLifecycleRoots(string value)
|
||||
{
|
||||
var pilot=ResolvePackagePilotRoot(value); string Child(string name)=>Path.GetFullPath(Path.Combine(pilot.Value,name));
|
||||
var paths=new[]{Child("catalog"),Child("staging"),Child("version-store"),Child("active"),Child("evidence")};
|
||||
if(paths.Distinct(StringComparer.OrdinalIgnoreCase).Count()!=paths.Length) throw new InvalidOperationException("PACKAGE_ROOT_COLLISION");
|
||||
foreach(var path in paths) if(!path.StartsWith(pilot.Value.TrimEnd(Path.DirectorySeparatorChar)+Path.DirectorySeparatorChar,StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("PACKAGE_ROOT_TOPOLOGY_INVALID");
|
||||
return new(pilot,new(paths[0]),new(paths[1]),new(paths[2]),new(paths[3]),new(paths[4]));
|
||||
}
|
||||
private string ResolveExistingFile(string role, LauncherPathVariables variables)
|
||||
{
|
||||
var value=ResolvePath(Resolve(variables,[role]).Require(role),variables);
|
||||
|
||||
Reference in New Issue
Block a user