Files
libnftables-dotnet/tests/LibNftables.Tests/NativeTestSupport.cs
Vibe Myass 3b523b78df
All checks were successful
smoke / smoke (push) Successful in 29s
Add root-aware privileged CI test lane
2026-03-16 04:36:14 +00:00

117 lines
3.0 KiB
C#

using System.Globalization;
namespace LibNftables.Tests;
internal static class NativeTestSupport
{
private const string PrivilegedTestsEnvironmentVariable = "LIBNFTABLES_RUN_PRIVILEGED_TESTS";
internal static bool IsRunningAsRoot()
{
if (!OperatingSystem.IsLinux())
{
return false;
}
try
{
foreach (var line in File.ReadLines("/proc/self/status"))
{
if (!line.StartsWith("Uid:", StringComparison.Ordinal))
{
continue;
}
var parts = line["Uid:".Length..]
.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
return parts.Length > 0 && parts[0] == "0";
}
}
catch
{
// If uid probing fails, keep tests conservative.
}
return false;
}
internal static bool PrivilegedTestsRequested()
{
var value = Environment.GetEnvironmentVariable(PrivilegedTestsEnvironmentVariable);
if (string.IsNullOrWhiteSpace(value))
{
return false;
}
return value.Equals("1", StringComparison.Ordinal)
|| value.Equals("true", StringComparison.OrdinalIgnoreCase)
|| value.Equals("yes", StringComparison.OrdinalIgnoreCase);
}
internal static bool ShouldRunPrivilegedTests()
{
return PrivilegedTestsRequested()
&& IsRunningAsRoot()
&& HasCapNetAdmin();
}
internal static bool HasCapNetAdmin()
{
const int capNetAdminBit = 12;
const ulong mask = 1UL << capNetAdminBit;
try
{
foreach (var line in File.ReadLines("/proc/self/status"))
{
if (!line.StartsWith("CapEff:", StringComparison.Ordinal))
{
continue;
}
var hex = line["CapEff:".Length..].Trim();
if (ulong.TryParse(hex, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var value))
{
return (value & mask) != 0;
}
}
}
catch
{
// If capability probing fails, keep tests conservative.
}
return false;
}
internal static bool TryCreateContext(out NftContext context)
{
try
{
context = new NftContext();
return true;
}
catch (DllNotFoundException)
{
context = null!;
return false;
}
catch (TypeInitializationException ex) when (ex.InnerException is DllNotFoundException)
{
context = null!;
return false;
}
catch (BadImageFormatException)
{
context = null!;
return false;
}
catch (EntryPointNotFoundException)
{
context = null!;
return false;
}
}
}