Nullean.ScopedFileSystem
0.7.2
dotnet add package Nullean.ScopedFileSystem --version 0.7.2
NuGet\Install-Package Nullean.ScopedFileSystem -Version 0.7.2
<PackageReference Include="Nullean.ScopedFileSystem" Version="0.7.2" />
<PackageVersion Include="Nullean.ScopedFileSystem" Version="0.7.2" />
<PackageReference Include="Nullean.ScopedFileSystem" />
paket add Nullean.ScopedFileSystem --version 0.7.2
#r "nuget: Nullean.ScopedFileSystem, 0.7.2"
#:package Nullean.ScopedFileSystem@0.7.2
#addin nuget:?package=Nullean.ScopedFileSystem&version=0.7.2
#tool nuget:?package=Nullean.ScopedFileSystem&version=0.7.2
Nullean.ScopedFileSystem

A System.IO.Abstractions IFileSystem decorator that restricts file reads and writes to one or more scope root directories and rejects symbolic links, hidden files and path traversal.
Install
dotnet add package Nullean.ScopedFileSystem
Quick start
using System.IO.Abstractions;
using Nullean.ScopedFileSystem;
IFileSystem scoped = new ScopedFileSystem("/var/www/docs");
var content = scoped.File.ReadAllText("/var/www/docs/page.md"); // OK: within scope
scoped.File.WriteAllText("/var/www/docs/output.md", content); // OK: write within scope
bool exists = scoped.File.Exists("/etc/passwd"); // false, no exception
scoped.File.ReadAllText("/etc/passwd"); // ScopedFileSystemException: outside scope
scoped.File.ReadAllText("/var/www/docs/../../../etc/passwd"); // ScopedFileSystemException: .. is resolved first
scoped.File.ReadAllText("/var/www/docs/.env"); // ScopedFileSystemException: hidden file
scoped.File.ReadAllText("/var/www/docs/link-to-secret"); // ScopedFileSystemException: symbolic link
Wrap any IFileSystem, such as a MockFileSystem in tests, and allow what else you need:
using System.IO.Abstractions;
using Nullean.ScopedFileSystem;
IFileSystem inner = new FileSystem(); // or a MockFileSystem in tests
IFileSystem scoped = new ScopedFileSystem(inner, new ScopedFileSystemOptions("/var/www/docs", "/var/www/data")
{
AllowedHiddenFolderNames = [".git"],
AllowedHiddenFileNames = [".gitkeep"],
AllowedSpecialFolders = AllowedSpecialFolder.Temp | AllowedSpecialFolder.ApplicationData,
});
scoped.File.WriteAllText(Path.Combine(Path.GetTempPath(), "cache.txt"), "ok"); // OK: temp is allowed
What it enforces
| Rule | Detail |
|---|---|
| Scope | The resolved path must be within a configured scope root or an explicitly allowed OS special folder. |
| No symlinks | The target and all ancestor directories up to the scope root must not be symbolic links. |
| No hidden files | Files whose name starts with . are blocked unless the name is in AllowedHiddenFileNames. |
| No hidden directories | Directories whose name starts with . are blocked unless the name is in AllowedHiddenFolderNames. This applies to both the target directory and all ancestors up to the scope root. |
| Exists is safe | File.Exists() and Directory.Exists() return false for out-of-scope paths instead of throwing. |
Any violation throws ScopedFileSystemException (extends SecurityException).
Any violation throws ScopedFileSystemException (extends SecurityException). Paths are resolved with
IPath.GetFullPath before any check, so .. cannot escape, and scope membership is checked by walking up the
directory tree, so /docs-extra is not inside /docs. Multiple roots must be disjoint, or the constructor throws
ArgumentException.
Learn more
- Multiple roots, hidden names, special folders and the options reference: https://github.com/nullean/scoped-filesystem#multiple-roots
- Source and issues: https://github.com/nullean/scoped-filesystem
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. net11.0 is compatible. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.IO.Abstractions (>= 23.0.0)
-
.NETStandard 2.1
- System.IO.Abstractions (>= 23.0.0)
-
net10.0
- System.IO.Abstractions (>= 23.0.0)
-
net11.0
- System.IO.Abstractions (>= 23.0.0)
-
net9.0
- System.IO.Abstractions (>= 23.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Nullean.ScopedFileSystem:
| Package | Downloads |
|---|---|
|
Nullean.Snapshots
Lightweight snapshot testing: the store, accept modes, scrubbers, the line differ and the failure message. |
GitHub repositories
This package is not used by any popular GitHub repositories.