From a74a1e807d6dd817e622a68f51beec689237bd81 Mon Sep 17 00:00:00 2001 From: Sergey Tihon Date: Sat, 3 Jan 2026 09:47:08 +0100 Subject: [PATCH 1/3] feat: add windows-latest ci --- .github/workflows/dotnetcore.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index aafc2b4..7c19a95 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest] + os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: From 583401501118e5680b132310ea9bf55977f159d2 Mon Sep 17 00:00:00 2001 From: Sergey Tihon Date: Sat, 3 Jan 2026 10:04:51 +0100 Subject: [PATCH 2/3] fix: normalize path --- src/SwaggerProvider.DesignTime/Utils.fs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/SwaggerProvider.DesignTime/Utils.fs b/src/SwaggerProvider.DesignTime/Utils.fs index 4317416..5254319 100644 --- a/src/SwaggerProvider.DesignTime/Utils.fs +++ b/src/SwaggerProvider.DesignTime/Utils.fs @@ -177,8 +177,10 @@ module SchemaReader = let possibleFilePath = try if Path.IsPathRooted resolvedPath then - // Already an absolute path - if File.Exists resolvedPath then Some resolvedPath else None + // Already a rooted path - normalize it to handle .. and . components + // This is important on Windows where paths like D:\foo\..\bar need normalization + let normalized = Path.GetFullPath resolvedPath + if File.Exists normalized then Some normalized else None else // Try to resolve relative paths (e.g., paths with ../ or from __SOURCE_DIRECTORY__) let resolved = Path.GetFullPath resolvedPath From 51720c6b6875e34fda85586f57d38f56d9f0e63b Mon Sep 17 00:00:00 2001 From: Sergey Tihon Date: Sat, 3 Jan 2026 10:10:35 +0100 Subject: [PATCH 3/3] fix: platform path detection --- src/SwaggerProvider.DesignTime/Utils.fs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/SwaggerProvider.DesignTime/Utils.fs b/src/SwaggerProvider.DesignTime/Utils.fs index 5254319..f5c72e6 100644 --- a/src/SwaggerProvider.DesignTime/Utils.fs +++ b/src/SwaggerProvider.DesignTime/Utils.fs @@ -198,12 +198,21 @@ module SchemaReader = | ex -> return failwithf "Error reading schema file '%s': %s" filePath ex.Message | None -> // Handle as remote URL (HTTP/HTTPS) - let checkUri = Uri(resolvedPath, UriKind.RelativeOrAbsolute) - // Only treat truly local paths as local files (no scheme or relative paths) - // Reject file:// scheme as unsupported to prevent SSRF attacks - let isLocalFile = not checkUri.IsAbsoluteUri - - if isLocalFile then + // First check if this looks like a local file path (Windows or Unix) + // On Windows, paths like D:\path are parsed as URIs with scheme "D", so we need special handling + let looksLikeWindowsPath = + resolvedPath.Length >= 2 + && Char.IsLetter(resolvedPath.[0]) + && resolvedPath.[1] = ':' + + let looksLikeUnixAbsolutePath = resolvedPath.StartsWith("/") + + // If it looks like a local file path, treat it as such (file not found) + if + looksLikeWindowsPath + || looksLikeUnixAbsolutePath + || not(resolvedPath.Contains("://")) + then // If we reach here with a local file that wasn't found, report the error return failwithf "Schema file not found: %s" resolvedPath else