feat: enforce resolved catalog path roles

This commit is contained in:
codex
2026-08-05 14:57:16 +03:00
parent 6fd670d08a
commit d6ed0ac592
3 changed files with 24 additions and 4 deletions
+19
View File
@@ -20,10 +20,19 @@ public sealed record ResolvedLauncherPaths(IReadOnlyDictionary<string, string?>
public string? FixtureOrthoDwg => Get(nameof(FixtureOrthoDwg));
}
/// <summary>Catalog source role resolved by <see cref="IPathResolver"/>. Raw
/// filesystem strings are intentionally not accepted by catalog acquisition.</summary>
public sealed record ResolvedCatalogRoot
{
internal ResolvedCatalogRoot(string value) => Value = value;
public string Value { get; }
}
public interface IPathResolver
{
ResolvedLauncherPaths Resolve(LauncherPathVariables variables, IEnumerable<string>? required = null);
string ResolvePath(string value, LauncherPathVariables variables, string? constrainedRoot = null);
ResolvedCatalogRoot ResolveCatalogRoot(LauncherPathVariables variables);
}
public sealed class PathResolver(IReadOnlyDictionary<string, string?>? environment = null) : IPathResolver
@@ -74,6 +83,16 @@ public sealed class PathResolver(IReadOnlyDictionary<string, string?>? environme
return full;
}
public ResolvedCatalogRoot ResolveCatalogRoot(LauncherPathVariables variables)
{
var resolved = Resolve(variables, [LauncherPathVariableNames.CorporateCatalogRoot, LauncherPathVariableNames.CorporateDfsRoot]);
var catalog = ResolvePath(resolved.Require(LauncherPathVariableNames.CorporateCatalogRoot), variables);
var corporate = ResolvePath(resolved.Require(LauncherPathVariableNames.CorporateDfsRoot), variables);
if (!catalog.StartsWith(corporate.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException("PATH_ROLE_COLLISION");
return new ResolvedCatalogRoot(catalog);
}
private string? ResolveVariable(string name, LauncherPathVariables variables, Dictionary<string, string?> resolved, HashSet<string> stack)
{
if (resolved.TryGetValue(name, out var cached)) return cached;