Skip to content

Comments

BED-7491#273

Open
lrfalslev wants to merge 6 commits intov4from
lfalslev/bed-7491
Open

BED-7491#273
lrfalslev wants to merge 6 commits intov4from
lfalslev/bed-7491

Conversation

@lrfalslev
Copy link
Contributor

@lrfalslev lrfalslev commented Feb 23, 2026

Description

Resolve compile time warnings for clean build output.

Motivation and Context

BED-7491

How Has This Been Tested?

Ran dotnet build succeeded with no errors/warnings
image

Types of changes

  • Chore (a change that does not modify the application functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • Documentation updates are needed, and have been made accordingly.
  • I have added and/or updated tests to cover my changes.
  • All new and existing tests passed.
  • My changes include a database migration.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed null-check logic in test mock utilities to prevent null reference exceptions.
    • Removed unused test variables.
  • Tests

    • Added Windows platform restrictions to Windows-specific tests for improved test isolation.
    • Improved cross-platform test compatibility by enabling a previously Windows-only test to run on all platforms.
  • Refactoring

    • Enhanced code quality through nullable reference type enablement across multiple modules.
    • Updated internal utility implementations for improved robustness.

@lrfalslev lrfalslev self-assigned this Feb 23, 2026
@lrfalslev lrfalslev added the bug Something isn't working label Feb 23, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

Walkthrough

This PR introduces nullable reference type annotations across multiple source files, adds Windows-only platform gating to numerous test methods using the [SupportedOSPlatform("windows")] attribute, updates method signatures for nullability compliance, refactors test helper classes, and adjusts package configuration settings for the AntiXSS dependency.

Changes

Cohort / File(s) Summary
Nullable Reference Type Enablement
src/CommonLib/Logging/Logging.cs, src/CommonLib/Ntlm/LdapTransport.cs, src/CommonLib/SMB/NetBIOS/NetBIOSSessionType.cs
Added #nullable enable directives (and corresponding #nullable disable at file end) to establish nullable context for proper reference type annotation handling.
Nullable Signature Updates in Processors
src/CommonLib/Processors/DCLdapProcessor.cs
Enabled nullable context and updated public signatures: constructor parameter ILogger logILogger? log, event ComputerStatusDelegateComputerStatusDelegate?, and method parameters NtlmAuthenticationHandler and LdapTransport → nullable variants.
Package Configuration
src/CommonLib/SharpHoundCommonLib.csproj
Added PrivateAssets="All" attribute to AntiXSS package reference to prevent asset visibility to consumers.
Windows Platform Gating in Tests
test/unit/ACLProcessorTest.cs, test/unit/CertAbuseProcessorTest.cs, test/unit/CommonLibHelperTests.cs, test/unit/DomainTrustProcessorTest.cs, test/unit/GPOLocalGroupProcessorTest.cs, test/unit/GroupProcessorTest.cs, test/unit/LDAPUtilsTest.cs, test/unit/LdapPropertyTests.cs, test/unit/LocalGroupProcessorTest.cs, test/unit/UserRightsAssignmentProcessorTest.cs
Added System.Runtime.Versioning using directive and [SupportedOSPlatform("windows")] attributes to restrict Windows-specific tests to Windows platforms only.
Test Utilities Refactoring
test/unit/Facades/FacadeHelpers.cs, test/unit/Facades/MockExtensions.cs
Replaced FormatterServices.GetUninitializedObject with RuntimeHelpers.GetUninitializedObject and renamed class from MockExtentions to MockExtensions; added null-check guard in log verification predicate.
Test Project Configuration
test/unit/CommonLibTest.csproj
Added NoWarn entry (NU1702) to suppress cross-targeting build warnings.
Test Cleanup
test/unit/DCLdapProcessorTest.cs, test/unit/WebClientServiceProcessorTest.cs
Removed unused local variable declarations in authentication tests and changed WebClientServiceProcessorTest_TestPathExists from [WindowsOnlyFact] to [Fact] for cross-platform execution.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • definitelynotagoblin
  • mykeelium

Poem

🐰 Hops of nullable delight,
Platform gates now shining bright,
Types made safer, tests refined,
Windows-wise, a thoughtful mind!
Changes clean, the code takes flight!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'BED-7491' is a ticket reference only and does not describe the actual change. It lacks specificity about what compile-time warnings were resolved. Use a descriptive title summarizing the main change, such as 'Resolve compile-time warnings for clean build output' or 'Enable nullable context and add platform gating attributes'.
Docstring Coverage ⚠️ Warning Docstring coverage is 2.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The PR description covers the template well with filled sections for Description, Motivation/Context (with ticket link), testing details (with screenshot), change type selection, and relevant checklist items.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch lfalslev/bed-7491

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
test/unit/WebClientServiceProcessorTest.cs (1)

29-35: ⚠️ Potential issue | 🟠 Major

Reintroduce OS platform gating for Windows-only API dependency.

WebClientServiceProcessor.IsWebClientRunning() directly uses kernel32.dll's CreateFile API to access Windows named pipes (\\{computerName}\pipe\DAV RPC SERVICE), which is not available on Linux/macOS. With [WindowsOnlyFact] removed, this test will throw PlatformNotSupportedException on non-Windows platforms. Restore the [WindowsOnlyFact] attribute and/or add [SupportedOSPlatform("windows")] to prevent cross-platform test failures.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit/WebClientServiceProcessorTest.cs` around lines 29 - 35, The test
WebClientServiceProcessorTest_TestPathExists calls
WebClientServiceProcessor.IsWebClientRunning which uses Windows-only
kernel32.dll CreateFile for named pipes; reintroduce platform gating by
restoring the [WindowsOnlyFact] attribute (or adding
[SupportedOSPlatform("windows")] on the test) so it only runs on Windows, or
alternatively annotate the IsWebClientRunning method with
[SupportedOSPlatform("windows")] to prevent PlatformNotSupportedException on
non-Windows platforms.
src/CommonLib/Processors/DCLdapProcessor.cs (3)

154-169: ⚠️ Potential issue | 🟡 Minor

Copy-paste error in CheckIsChannelBindingDisabled error message.

Line 168 returns "CheckIsNtlmSigningRequired failed: ..." when the failing method is CheckIsChannelBindingDisabled.

🐛 Proposed fix
-            return SharpHoundRPC.Result<bool>.Fail($"CheckIsNtlmSigningRequired failed: {ex}");
+            return SharpHoundRPC.Result<bool>.Fail($"CheckIsChannelBindingDisabled failed: {ex}");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/CommonLib/Processors/DCLdapProcessor.cs` around lines 154 - 169, The
error message in CheckIsChannelBindingDisabled incorrectly references
"CheckIsNtlmSigningRequired"; update the failure return in the catch block of
CheckIsChannelBindingDisabled to use the correct method name (e.g.,
"CheckIsChannelBindingDisabled failed: {ex}") so the returned
SharpHoundRPC.Result<bool>.Fail message accurately identifies the failing
function and includes the exception details.

81-88: ⚠️ Potential issue | 🟡 Minor

Copy-paste bug: isSigningRequired.Status logged in the isChannelBindingDisabled.IsFailed branch.

Line 88 logs isSigningRequired.Status instead of isChannelBindingDisabled.Status, making failure diagnostics for the channel-binding check misleading.

🐛 Proposed fix
-            _log.LogTrace("DCLdapScan failed on IsChannelBindingDisabled for {ComputerName}: {Status}", computerName, isSigningRequired.Status);
+            _log.LogTrace("DCLdapScan failed on IsChannelBindingDisabled for {ComputerName}: {Status}", computerName, isChannelBindingDisabled.Status);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/CommonLib/Processors/DCLdapProcessor.cs` around lines 81 - 88, The log in
the isChannelBindingDisabled failure branch mistakenly references
isSigningRequired.Status; update the DCLdapProcessor failure handling so the
trace log uses isChannelBindingDisabled.Status (the same result used for
SendComputerStatus) — locate the branch around the SendComputerStatus call for
DCLdapIsChannelBindingDisabled and replace the incorrect
isSigningRequired.Status reference in the _log.LogTrace call with
isChannelBindingDisabled.Status to ensure accurate diagnostics.

178-228: ⚠️ Potential issue | 🟠 Major

LdapTransport created locally in Authenticate is never disposed — native LDAP handle leak.

When ldapTransport is null (always the case for calls from CheckIsNtlmSigningRequired and CheckIsChannelBindingDisabled), a new LdapTransport is created at line 183 but never disposed. LdapTransport implements IDisposable and wraps a native LdapConnection; omitting disposal leaks the unmanaged handle on every scan call.

🔧 Proposed fix — dispose only the locally-owned transport
 protected internal virtual async Task<bool> Authenticate(Uri endpoint, LdapAuthOptions options, NtlmAuthenticationHandler? ntlmAuth = null, LdapTransport? ldapTransport = null, CancellationToken cancellationToken = default) {
     var host = endpoint.Host;
     var auth = ntlmAuth ?? new NtlmAuthenticationHandler($"LDAP/{host.ToUpper()}") {
         Options = options
     };
-    var transport = ldapTransport ?? new LdapTransport(_log, endpoint);
+    var ownedTransport = ldapTransport is null ? new LdapTransport(_log, endpoint) : null;
+    var transport = ownedTransport ?? ldapTransport!;
 
     try {
         transport.InitializeConnectionAsync(_ldapTimeout);
         await auth.PerformNtlmAuthenticationAsync(transport, cancellationToken);
         return true;
     } catch (LdapNativeException ex) {
         // ... existing catch blocks ...
-    }
+    } finally {
+        ownedTransport?.Dispose();
+    }
 
     return false;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/CommonLib/Processors/DCLdapProcessor.cs` around lines 178 - 228, The
Authenticate method creates a new LdapTransport when the ldapTransport parameter
is null but never disposes it, leaking the native LdapConnection; update
Authenticate so that when you instantiate a local transport (the local variable
transport when ldapTransport == null) you dispose it after use (e.g., wrap the
created LdapTransport in a using or try/finally that calls Dispose) while
ensuring you do not dispose the incoming ldapTransport parameter passed by
callers (only dispose the locally-owned instance). Ensure this change references
the Authenticate method, the ldapTransport parameter, the transport local
variable, and the LdapTransport type so only the locally-created instance is
cleaned up.
🧹 Nitpick comments (2)
test/unit/Facades/MockExtensions.cs (1)

32-33: VerifyLog is inconsistent with the null-guard added to VerifyLogContains.

VerifyLogContains now explicitly checks o != null before dereferencing, but VerifyLog calls o.ToString() without a null guard. In the #nullable enable context this will also emit a nullable warning for o.ToString(). Aligning the two predicates makes the guard explicit and silences the warning.

♻️ Proposed fix for consistency and nullable compliance
-                It.Is<It.IsAnyType>((o, t) =>
-                    string.Equals(expectedMessage, o.ToString(), StringComparison.InvariantCultureIgnoreCase)),
+                It.Is<It.IsAnyType>((o, t) =>
+                    o != null &&
+                    string.Equals(expectedMessage, o.ToString()!, StringComparison.InvariantCultureIgnoreCase)),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit/Facades/MockExtensions.cs` around lines 32 - 33, VerifyLog
currently calls o.ToString() without a null guard, causing a nullable warning
and inconsistency with VerifyLogContains; update the predicate used in VerifyLog
(the It.Is<It.IsAnyType>((o, t) => ... ) lambda) to check o != null before
calling ToString(), e.g. change the predicate to ensure o != null &&
string.Equals(expectedMessage, o.ToString(),
StringComparison.InvariantCultureIgnoreCase) so it matches VerifyLogContains and
silences the nullable warning.
src/CommonLib/Ntlm/LdapTransport.cs (1)

37-37: InitializeConnectionAsync misleadingly named — it is synchronous (void).

The Async suffix implies a Task-returning awaitable. Callers (DCLdapProcessor.Authenticate, line 186) call it without await and the compiler CA1849 / naming analyzer can flag this. Consider renaming to InitializeConnection and adding a proper Task-returning async overload if needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/CommonLib/Ntlm/LdapTransport.cs` at line 37, The method
InitializeConnectionAsync is misleadingly named but is synchronous; rename the
method to InitializeConnection (update its declaration and all call sites, e.g.,
DCLdapProcessor.Authenticate) to satisfy naming conventions, and if asynchronous
behavior is required later add an async Task-returning overload
InitializeConnectionAsync(int timeout = -1) that performs the async work; ensure
call sites either call the new synchronous InitializeConnection or await the new
Task-based InitializeConnectionAsync as appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/CommonLib/Processors/DCLdapProcessor.cs`:
- Around line 154-169: The error message in CheckIsChannelBindingDisabled
incorrectly references "CheckIsNtlmSigningRequired"; update the failure return
in the catch block of CheckIsChannelBindingDisabled to use the correct method
name (e.g., "CheckIsChannelBindingDisabled failed: {ex}") so the returned
SharpHoundRPC.Result<bool>.Fail message accurately identifies the failing
function and includes the exception details.
- Around line 81-88: The log in the isChannelBindingDisabled failure branch
mistakenly references isSigningRequired.Status; update the DCLdapProcessor
failure handling so the trace log uses isChannelBindingDisabled.Status (the same
result used for SendComputerStatus) — locate the branch around the
SendComputerStatus call for DCLdapIsChannelBindingDisabled and replace the
incorrect isSigningRequired.Status reference in the _log.LogTrace call with
isChannelBindingDisabled.Status to ensure accurate diagnostics.
- Around line 178-228: The Authenticate method creates a new LdapTransport when
the ldapTransport parameter is null but never disposes it, leaking the native
LdapConnection; update Authenticate so that when you instantiate a local
transport (the local variable transport when ldapTransport == null) you dispose
it after use (e.g., wrap the created LdapTransport in a using or try/finally
that calls Dispose) while ensuring you do not dispose the incoming ldapTransport
parameter passed by callers (only dispose the locally-owned instance). Ensure
this change references the Authenticate method, the ldapTransport parameter, the
transport local variable, and the LdapTransport type so only the locally-created
instance is cleaned up.

In `@test/unit/WebClientServiceProcessorTest.cs`:
- Around line 29-35: The test WebClientServiceProcessorTest_TestPathExists calls
WebClientServiceProcessor.IsWebClientRunning which uses Windows-only
kernel32.dll CreateFile for named pipes; reintroduce platform gating by
restoring the [WindowsOnlyFact] attribute (or adding
[SupportedOSPlatform("windows")] on the test) so it only runs on Windows, or
alternatively annotate the IsWebClientRunning method with
[SupportedOSPlatform("windows")] to prevent PlatformNotSupportedException on
non-Windows platforms.

---

Nitpick comments:
In `@src/CommonLib/Ntlm/LdapTransport.cs`:
- Line 37: The method InitializeConnectionAsync is misleadingly named but is
synchronous; rename the method to InitializeConnection (update its declaration
and all call sites, e.g., DCLdapProcessor.Authenticate) to satisfy naming
conventions, and if asynchronous behavior is required later add an async
Task-returning overload InitializeConnectionAsync(int timeout = -1) that
performs the async work; ensure call sites either call the new synchronous
InitializeConnection or await the new Task-based InitializeConnectionAsync as
appropriate.

In `@test/unit/Facades/MockExtensions.cs`:
- Around line 32-33: VerifyLog currently calls o.ToString() without a null
guard, causing a nullable warning and inconsistency with VerifyLogContains;
update the predicate used in VerifyLog (the It.Is<It.IsAnyType>((o, t) => ... )
lambda) to check o != null before calling ToString(), e.g. change the predicate
to ensure o != null && string.Equals(expectedMessage, o.ToString(),
StringComparison.InvariantCultureIgnoreCase) so it matches VerifyLogContains and
silences the nullable warning.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 52b978a and a705a68.

📒 Files selected for processing (20)
  • src/CommonLib/Logging/Logging.cs
  • src/CommonLib/Ntlm/LdapTransport.cs
  • src/CommonLib/Processors/DCLdapProcessor.cs
  • src/CommonLib/SMB/NetBIOS/NetBIOSSessionType.cs
  • src/CommonLib/SharpHoundCommonLib.csproj
  • test/unit/ACLProcessorTest.cs
  • test/unit/CertAbuseProcessorTest.cs
  • test/unit/CommonLibHelperTests.cs
  • test/unit/CommonLibTest.csproj
  • test/unit/DCLdapProcessorTest.cs
  • test/unit/DomainTrustProcessorTest.cs
  • test/unit/Facades/FacadeHelpers.cs
  • test/unit/Facades/MockExtensions.cs
  • test/unit/GPOLocalGroupProcessorTest.cs
  • test/unit/GroupProcessorTest.cs
  • test/unit/LDAPUtilsTest.cs
  • test/unit/LdapPropertyTests.cs
  • test/unit/LocalGroupProcessorTest.cs
  • test/unit/UserRightsAssignmentProcessorTest.cs
  • test/unit/WebClientServiceProcessorTest.cs
💤 Files with no reviewable changes (1)
  • test/unit/DCLdapProcessorTest.cs


internal static T GetUninitializedObject<T>()
{
return (T) FormatterServices.GetUninitializedObject(typeof(T));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FormatterServices has been deprecated.

SYSLIB0050: Class 'System.Runtime.Serialization.FormatterServices' is obsolete: 'Formatter-based serialization is obsolete and should not be used.'

</PropertyGroup>
<ItemGroup>
<PackageReference Include="AntiXSS" Version="4.3.0" />
<PackageReference Include="AntiXSS" Version="4.3.0" PrivateAssets="All"/>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marked as private to avoid transitive nuget restore in test projects.

warning NU1701: Package 'AntiXSS 4.3.0' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8, .NETFramework,Version=v4.8.1' instead of the project target framework 'net8.0'. This package may not be fully compatible with your project.

<CoverletOutput>..\..\docfx\coverage\</CoverletOutput>
<CoverletOutputFormat>OpenCover</CoverletOutputFormat>
<!-- Suppress cross-targeting warning when referencing net472 SharpHound projects in net8.0 tests -->
<NoWarn>$(NoWarn);NU1702</NoWarn>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning NU1702: ProjectReference 'SharpHoundCommon\src\CommonLib\SharpHoundCommonLib.csproj' was resolved using '.NETFramework,Version=v4.7.2' instead of the project target framework '.NETCoreApp,Version=v8.0'. This project may not be fully compatible with your project.

Assert.False(result);
}

[SupportedOSPlatform("windows")]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolves warning CA1416: This call site is reachable on all platforms.

@@ -1,4 +1,5 @@

#nullable enable
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants