mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-05 03:42:10 -04:00
fix(defaults): treat a read-denied defaults file as invalid
NestDefaults.Load caught only JsonException and IOException, so a defaults.json that File.Exists can see but the process cannot read threw UnauthorizedAccessException out of New. Report such files as Invalid and return the fallback values, like a corrupt file. The regression mode-000s the file on Unix (skipped on Windows and when running as root); it failed with UnauthorizedAccessException before this change.
This commit is contained in:
1 parent
23d258b886
commit
39a15aee14
2 files changed
+42
-6
No files matched your search
@@ -88,13 +88,10 @@ public sealed class NestDefaults
|
||||
var json = File.ReadAllText(path);
|
||||
dto = JsonSerializer.Deserialize<NestDefaultsDto>(json, JsonOptions);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
status = NestDefaultsStatus.Invalid;
|
||||
return defaults;
|
||||
}
|
||||
catch (IOException)
|
||||
catch (Exception ex) when (IsUnreadableFile(ex))
|
||||
{
|
||||
// A file that exists but cannot be read (locked, access-denied)
|
||||
// or parsed must never block creating a nest.
|
||||
status = NestDefaultsStatus.Invalid;
|
||||
return defaults;
|
||||
}
|
||||
@@ -228,6 +225,14 @@ public sealed class NestDefaults
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsUnreadableFile(Exception ex) =>
|
||||
ex
|
||||
is JsonException
|
||||
or IOException
|
||||
or UnauthorizedAccessException
|
||||
or NotSupportedException
|
||||
or System.Security.SecurityException;
|
||||
|
||||
private static bool IsValidSize(double width, double length) =>
|
||||
!double.IsNaN(width)
|
||||
&& !double.IsNaN(length)
|
||||
|
||||
@@ -75,6 +75,24 @@ public class NestDefaultsTests : IDisposable
|
||||
AssertFallback(loaded);
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void Load_ReadDeniedFile_ReturnsFallbackButReportsInvalid()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
throw new SkipException("Unix file modes deny the read on Linux/macOS");
|
||||
|
||||
new NestDefaults { PartSpacing = 4 }.Save(_path);
|
||||
File.SetUnixFileMode(_path, UnixFileMode.None);
|
||||
Skip.If(CanRead(_path), "Process can read a mode-000 file (running as root)");
|
||||
|
||||
// The file is visible to File.Exists, but reading it is denied.
|
||||
Assert.True(File.Exists(_path));
|
||||
var loaded = NestDefaults.Load(_path, out var status);
|
||||
|
||||
Assert.Equal(NestDefaultsStatus.Invalid, status);
|
||||
AssertFallback(loaded);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_PartialFile_MergesPerField()
|
||||
{
|
||||
@@ -198,6 +216,19 @@ public class NestDefaultsTests : IDisposable
|
||||
Assert.Equal(new Size(48, 96), defaults.Size);
|
||||
}
|
||||
|
||||
private static bool CanRead(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var _ = File.OpenRead(path);
|
||||
return true;
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertFallback(NestDefaults loaded)
|
||||
{
|
||||
Assert.Equal(Units.Inches, loaded.Units);
|
||||
|
||||
Reference in new issue
Block a user