From 4f36ec720cf3194a800eb42072c9f1dcc1f33e8c Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Tue, 8 Sep 2026 13:55:48 +0100 Subject: [PATCH 1/3] Fix ToAppSafeFileName to handle both path separators Path.GetFileName/GetDirectoryName only recognize the current OS's path separator, so a Windows-style path (backslashes) passed to ToAppSafeFileName on Linux was left completely untouched instead of having app.config/web.config renamed - GetFileName returned the whole string unchanged since there was no '/' to split on, so the bad-name check never matched. Discovered while testing whether the build/test workflows could move to ubuntu-latest runners: PathNameTests.BadFileNamesAreAppended failed on Linux for exactly this reason. Now splits on both '\' and '/' manually so the result doesn't depend on which OS is parsing the path. Co-Authored-By: Claude Sonnet 5 --- uSync.Core/Extensions/StringExtensions.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/uSync.Core/Extensions/StringExtensions.cs b/uSync.Core/Extensions/StringExtensions.cs index 5e11f530..e8999d87 100644 --- a/uSync.Core/Extensions/StringExtensions.cs +++ b/uSync.Core/Extensions/StringExtensions.cs @@ -16,14 +16,22 @@ public static class StringExtensions /// /// convert a file name to one that isn't going to cause us any downlevel problems. /// + /// + /// paths aren't always parsed on the OS they came from (e.g. a Windows-style path + /// loaded on Linux), so we split on both separators here rather than using + /// Path.GetFileName/GetDirectoryName, which only recognise the current OS's separator. + /// public static string ToAppSafeFileName(this string value) { - var filename = Path.GetFileName(value); + var separatorIndex = value.LastIndexOfAny(['\\', '/']); + var directory = separatorIndex >= 0 ? value[..(separatorIndex + 1)] : string.Empty; + var filename = separatorIndex >= 0 ? value[(separatorIndex + 1)..] : value; + if (_badNames.InvariantContains(filename)) { - return Path.Combine( - Path.GetDirectoryName(value) ?? string.Empty, - $"__{Path.GetFileNameWithoutExtension(value)}__{Path.GetExtension(value)}"); + var extension = Path.GetExtension(filename); + var nameWithoutExtension = filename[..^extension.Length]; + return $"{directory}__{nameWithoutExtension}__{extension}"; } return value; } From 35af08660c2a37248cafec96df5a1c4dcf5643ce Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Tue, 8 Sep 2026 13:55:56 +0100 Subject: [PATCH 2/3] test: verify fix on ubuntu-latest (throwaway, do not merge) --- .github/workflows/dotnet-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml index edb0731b..9b19be72 100644 --- a/.github/workflows/dotnet-build.yml +++ b/.github/workflows/dotnet-build.yml @@ -15,7 +15,7 @@ env: jobs: build-project: - runs-on: windows-latest + runs-on: ubuntu-latest env: solution_name: ./uSync.slnx From d62cf2d67e5492c4c3dde5bf474419792673b379 Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Tue, 8 Sep 2026 13:59:52 +0100 Subject: [PATCH 3/3] test: also fix env.Config casing to verify full green run (throwaway) --- .github/workflows/dotnet-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml index 9b19be72..39e58ddf 100644 --- a/.github/workflows/dotnet-build.yml +++ b/.github/workflows/dotnet-build.yml @@ -40,4 +40,4 @@ jobs: run: dotnet test ${{ env.solution_name }} - name: Generate AppSettings Schema - run: dotnet run -c ${{env.Config}} --project ${{ env.schema_gen_project}} + run: dotnet run -c ${{ env.config }} --project ${{ env.schema_gen_project}}