Skip to content

Conversation

@definitelynotagoblin
Copy link
Contributor

@definitelynotagoblin definitelynotagoblin commented Jul 9, 2025

Description

A first step towards execution time analytics.
Adding self-configuring timeouts to existing timeout wrappers.

Motivation and Context

https://specterops.atlassian.net/browse/BED-5972
https://specterops.atlassian.net/browse/BED-6198

How Has This Been Tested?

Unit tests, local lab

Screenshots (if appropriate):

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

Summary by CodeRabbit

  • New Features

    • Introduced adaptive timeout handling across various operations, replacing fixed timeout values with dynamic, self-adjusting timeouts based on recent execution times.
    • Added new adaptive timeout and execution time sampling utilities for improved reliability and performance.
  • Improvements

    • Updated multiple processor and utility classes to use adaptive timeouts, enhancing robustness against network variability and operational delays.
    • Simplified method signatures by removing explicit timeout parameters where adaptive timeouts are now applied.
    • Enhanced cancellation support for timeout operations.
    • Centralized and standardized timeout management in network, RPC, and LDAP calls.
    • Improved LDAP request handling with adaptive timeouts and retry logic for timeouts.
  • Bug Fixes

    • Improved timeout management to better handle sudden spikes and prevent skewed timeout calculations.
  • Tests

    • Added comprehensive unit tests for adaptive timeout logic.
    • Updated or commented out obsolete timeout-related tests to reflect new adaptive timeout mechanisms.

@definitelynotagoblin definitelynotagoblin self-assigned this Jul 9, 2025
@definitelynotagoblin definitelynotagoblin added the enhancement New feature or request label Jul 9, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 9, 2025

## Walkthrough

This update introduces an adaptive timeout mechanism throughout the codebase by implementing new `AdaptiveTimeout` and `ExecutionTimeSampler` classes. Numerous processors, utilities, and services are refactored to use adaptive timeouts instead of static or hardcoded values. Public method signatures are updated to remove explicit timeout parameters, and corresponding tests are adjusted or commented out to reflect the new adaptive approach.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `src/CommonLib/AdaptiveTimeout.cs`, `src/CommonLib/ExecutionTimeSampler.cs` | Added new classes for adaptive timeout and execution time sampling, providing dynamic timeout calculation and statistics. |
| `src/CommonLib/IRegistryKey.cs`, `src/CommonLib/LdapUtils.cs`, `src/CommonLib/Ntlm/HttpNtlmAuthenticationService.cs`, `src/CommonLib/Processors/CertAbuseProcessor.cs`, `src/CommonLib/Processors/ComputerSessionProcessor.cs`, `src/CommonLib/Processors/DCLdapProcessor.cs`, `src/CommonLib/Processors/LocalGroupProcessor.cs`, `src/CommonLib/Processors/PortScanner.cs`, `src/CommonLib/Processors/SmbProcessor.cs`, `src/CommonLib/Processors/UserRightsAssignmentProcessor.cs`, `src/CommonLib/SMB/SmbScanner.cs` | Refactored to use `AdaptiveTimeout` instances for operation timeouts; removed or updated timeout parameters in public methods and constructors. |
| `src/CommonLib/Timeout.cs` | Added optional `CancellationToken` parameters to timeout execution wrappers for improved cancellation support. |
| `src/CommonLib/LdapConnectionPool.cs` | Added adaptive timeout handling for LDAP queries with retry logic on timeout exceptions. |
| `src/SharpHoundRPC/PortScanner/IPortScanner.cs` | Updated `CheckPort` interface method to remove the timeout parameter. |
| `test/unit/AdaptiveTimeoutTest.cs` | Added new unit tests for `AdaptiveTimeout` covering adaptive calculation, disabling, and spike handling. |
| `test/unit/ComputerAvailabilityTests.cs`, `test/unit/LocalGroupProcessorTest.cs` | Updated mocks and test calls to match new method signatures without timeout parameters. |
| `test/unit/ComputerSessionProcessorTest.cs`, `test/unit/DCLdapProcessorTest.cs`, `test/unit/HttpNtlmAuthenticationServiceTest.cs`, `test/unit/UserRightsAssignmentProcessorTest.cs` | Commented out or marked as obsolete several timeout-specific tests due to the new adaptive timeout mechanism; adjusted event handlers to match updated signatures. |
| `test/unit/SmbProcessorTest.cs` | Updated event handler and removed explicit timeout argument in test call. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Caller
    participant AdaptiveTimeout
    participant ExecutionTimeSampler
    participant TargetOperation

    Caller->>AdaptiveTimeout: ExecuteWithTimeout(Func)
    AdaptiveTimeout->>ExecutionTimeSampler: SampleExecutionTime(Func)
    ExecutionTimeSampler->>TargetOperation: Invoke operation
    TargetOperation-->>ExecutionTimeSampler: Return result
    ExecutionTimeSampler-->>AdaptiveTimeout: Record timing sample
    AdaptiveTimeout-->>Caller: Return result (with adaptive timeout enforcement)

Suggested reviewers

  • ktstrader
  • MikeX777

Poem

🐇
Adaptive timeouts, clever and spry,
Now watch our functions as milliseconds fly.
No more fixed waits or tests that stall—
The sampler learns, the code stands tall!
Rabbits rejoice as deadlines adjust,
For timing that’s fair, efficient, and just.
⏱️✨


<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 3e9ed5f0ce199a8e27111608f5afea18c62cd965 and d39465c4eb55b3dccd56c1d2563af10e0adb7437.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `src/CommonLib/Processors/PortScanner.cs` (3 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* src/CommonLib/Processors/PortScanner.cs

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary>

* GitHub Check: build

</details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=SpecterOps/SharpHoundCommon&utm_content=222):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@definitelynotagoblin definitelynotagoblin changed the title Log timeout-wrapped execution time stats, add adaptive timeout logic [BED-5972] Log timeout-wrapped execution time stats, add adaptive timeout logic Jul 11, 2025
@definitelynotagoblin definitelynotagoblin marked this pull request as ready for review July 11, 2025 20:05
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.

Actionable comments posted: 12

🔭 Outside diff range comments (3)
src/CommonLib/Processors/DCLdapProcessor.cs (1)

83-83: Fix copy-paste error in log message

The log message uses isSigningRequired.Status instead of isChannelBindingDisabled.Status.

-_log.LogTrace("DCLdapScan failed on IsChannelBindingDisabled for {ComputerName}: {Status}", computerName, isSigningRequired.Status);
+_log.LogTrace("DCLdapScan failed on IsChannelBindingDisabled for {ComputerName}: {Status}", computerName, isChannelBindingDisabled.Status);
src/CommonLib/Processors/LocalGroupProcessor.cs (1)

43-52: Avoid blocking on async code to prevent deadlocks

Using .GetAwaiter().GetResult() blocks synchronously on async code, which can cause deadlocks in certain contexts (e.g., UI threads, ASP.NET contexts).

Consider making this method async:

-public virtual SharpHoundRPC.Result<ISAMServer> OpenSamServer(string computerName)
+public virtual async Task<SharpHoundRPC.Result<ISAMServer>> OpenSamServerAsync(string computerName)
{
-    var result = _openSamServerAdaptiveTimeout.ExecuteRPCWithTimeout((_) => SAMServer.OpenServer(computerName)).GetAwaiter().GetResult();
+    var result = await _openSamServerAdaptiveTimeout.ExecuteRPCWithTimeout((_) => SAMServer.OpenServer(computerName));
    if (result.IsFailed)
    {
        return SharpHoundRPC.Result<ISAMServer>.Fail(result.SError);
    }
    
    return SharpHoundRPC.Result<ISAMServer>.Ok(result.Value); 
}

Then update the call site at line 72:

-var openServerResult = OpenSamServer(computerName);
+var openServerResult = await OpenSamServerAsync(computerName);
src/CommonLib/Ntlm/HttpNtlmAuthenticationService.cs (1)

162-162: Fix copy-paste error in exception message

The exception message says "CheckIsNtlmSigningRequired failed" but this is in the CheckIsChannelBindingDisabled method.

-return SharpHoundRPC.Result<bool>.Fail($"CheckIsNtlmSigningRequired failed: {ex}");
+return SharpHoundRPC.Result<bool>.Fail($"CheckIsChannelBindingDisabled failed: {ex}");
🧹 Nitpick comments (5)
test/unit/HttpNtlmAuthenticationServiceTest.cs (1)

80-89: Consider cleaning up commented test code.

While commenting out timeout-specific tests during the adaptive timeout refactoring is understandable, consider either:

  1. Removing the commented tests entirely to reduce code clutter
  2. Replacing them with tests that verify the new adaptive timeout behavior

Keeping commented code long-term impacts maintainability and code clarity.

Apply this diff to clean up the commented code:

-        // Obsolete by AdaptiveTimeout
-        // [Fact]
-        // public void HttpNtlmAuthenticationService_EnsureRequiresAuth_GetSupportedNtlmAuthSchemesAsync_Timeout() {
-        //     var url = new Uri("http://primary.testlab.local/");
-        //     var service = new HttpNtlmAuthenticationService(new HttpClientFactory(), null);
-        //     var ex = Assert.ThrowsAsync<TimeoutException>(() =>
-        //         service.EnsureRequiresAuth(url, true));
-        //     Assert.Equal($"Timeout getting supported NTLM auth schemes for {url}", ex.Result.Message);
-
-        // }
-
-        // Obsolete by AdaptiveTimeout
-        // [Fact]
-        // public void HttpNtlmAuthenticationService_AuthWithBadChannelBindingsAsync_Timeout() {
-        //     var url = new Uri("http://primary.testlab.local/");
-        //     var authScheme = "NTLM";
-        //     var service = new HttpNtlmAuthenticationService(new HttpClientFactory(), null);
-        //     var httpResponseMessage = new HttpResponseMessage {
-        //         StatusCode = HttpStatusCode.InternalServerError,
-        //     };
-        //     var mockAuthenticator = new Mock<NtlmAuthenticationHandler>(It.IsAny<string>(), null);
-        //     mockAuthenticator.Setup(x =>
-        //         x.PerformNtlmAuthenticationAsync(It.IsAny<INtlmTransport>(), It.IsAny<CancellationToken>())).Returns(async () => {
-        //             await Task.Delay(1000);
-        //             return httpResponseMessage;
-        //         });
-
-        //     var ex = Assert.ThrowsAsync<TimeoutException>(async () => await TestPrivateMethod.InstanceMethod<Task>(service,
-        //         "AuthWithBadChannelBindingsAsync",
-        //         [
-        //             url, authScheme, TimeSpan.FromMilliseconds(1), mockAuthenticator.Object
-        //         ]));
-        //     Assert.Equal($"Timeout during NTLM authentication for {url} with {authScheme}", ex.Result.Message);
-
-        // }

Also applies to: 91-114

test/unit/ComputerSessionProcessorTest.cs (1)

219-257: Consider adding tests for the new adaptive timeout mechanism.

While commenting out the obsolete timeout tests makes sense given the architectural shift to adaptive timeouts, consider whether equivalent tests should be added to verify the adaptive timeout behavior. The current approach leaves untested code paths that were previously covered.

Consider either:

  1. Adding new tests that verify the adaptive timeout mechanism works as expected
  2. Removing the commented code entirely to reduce maintenance burden

Additionally, verify that the adaptive timeout mechanism provides adequate coverage for the scenarios these tests previously validated.

test/unit/UserRightsAssignmentProcessorTest.cs (1)

71-92: Test coverage gap for adaptive timeout mechanism.

The commented-out timeout test leaves a coverage gap for the new adaptive timeout functionality. Consider adding tests to verify that the UserRightsAssignmentProcessor correctly handles timeout scenarios with the new adaptive timeout mechanism.

Consider adding a new test that verifies the adaptive timeout behavior or remove the commented code entirely to reduce maintenance overhead.

src/CommonLib/ExecutionTimeSampler.cs (1)

35-41: Optimize statistical calculations for performance.

The StandardDeviation() method performs O(n) calculations every time it's called, which can be expensive when called frequently (especially during logging). Consider caching the result or using an incremental calculation approach.

+private double? _cachedStandardDeviation;
+private double? _cachedAverage;
+private int _lastCalculationCount;

public double StandardDeviation() {
+    if (_samples.Count == _lastCalculationCount && _cachedStandardDeviation.HasValue) {
+        return _cachedStandardDeviation.Value;
+    }
+    
    double average = _samples.Average();
    double sumOfSquaresOfDifferences = _samples.Select(val => (val - average) * (val - average)).Sum();
    double stddiv = Math.Sqrt(sumOfSquaresOfDifferences / _samples.Count);
    
+    _cachedStandardDeviation = stddiv;
+    _cachedAverage = average;
+    _lastCalculationCount = _samples.Count;
+    
    return stddiv;
}
src/CommonLib/AdaptiveTimeout.cs (1)

165-165: Fix typo in comment

The comment has a typo in "Tchebysheff's Rule".

-// https://modelassist.epixanalytics.com/space/EA/26574957/Tchebysheffs+Rule
+// https://modelassist.epixanalytics.com/space/EA/26574957/Chebyshev's+Rule
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ad304b and 0cbd7bf.

📒 Files selected for processing (24)
  • src/CommonLib/AdaptiveTimeout.cs (1 hunks)
  • src/CommonLib/ExecutionTimeSampler.cs (1 hunks)
  • src/CommonLib/IRegistryKey.cs (3 hunks)
  • src/CommonLib/LdapUtils.cs (3 hunks)
  • src/CommonLib/Ntlm/HttpNtlmAuthenticationService.cs (5 hunks)
  • src/CommonLib/Processors/CertAbuseProcessor.cs (3 hunks)
  • src/CommonLib/Processors/ComputerAvailability.cs (3 hunks)
  • src/CommonLib/Processors/ComputerSessionProcessor.cs (4 hunks)
  • src/CommonLib/Processors/DCLdapProcessor.cs (3 hunks)
  • src/CommonLib/Processors/LocalGroupProcessor.cs (9 hunks)
  • src/CommonLib/Processors/PortScanner.cs (3 hunks)
  • src/CommonLib/Processors/SmbProcessor.cs (1 hunks)
  • src/CommonLib/Processors/UserRightsAssignmentProcessor.cs (4 hunks)
  • src/CommonLib/SMB/SmbScanner.cs (2 hunks)
  • src/CommonLib/Timeout.cs (3 hunks)
  • src/SharpHoundRPC/PortScanner/IPortScanner.cs (1 hunks)
  • test/unit/AdaptiveTimeoutTest.cs (1 hunks)
  • test/unit/ComputerAvailabilityTests.cs (1 hunks)
  • test/unit/ComputerSessionProcessorTest.cs (1 hunks)
  • test/unit/DCLdapProcessorTest.cs (3 hunks)
  • test/unit/HttpNtlmAuthenticationServiceTest.cs (1 hunks)
  • test/unit/LocalGroupProcessorTest.cs (12 hunks)
  • test/unit/SmbProcessorTest.cs (1 hunks)
  • test/unit/UserRightsAssignmentProcessorTest.cs (1 hunks)
🧰 Additional context used
🧠 Learnings (16)
test/unit/UserRightsAssignmentProcessorTest.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:17-36
Timestamp: 2025-06-26T16:38:49.677Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team initially had concerns about disposing CancellationTokenSource instances before tasks could check cancellation tokens, but they understand that orphaned tasks (those that exceed timeout) won't be impacted by disposed tokens since their results are already ignored by the timeout handler. They prefer proper resource management with using statements for CancellationTokenSource disposal.
src/CommonLib/LdapUtils.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/LdapConnectionPool.cs:677-677
Timestamp: 2025-06-26T16:59:06.972Z
Learning: In SharpHoundCommonLib's LdapConnectionPool.cs, the team acknowledges that method `GetConnectionForSpecificServerAsync` has misleading naming - it contains "Async" in the name but is actually synchronous and blocks on async code, which they recognize as confusing but may need to live with due to backwards compatibility constraints.
src/SharpHoundRPC/PortScanner/IPortScanner.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:21-21
Timestamp: 2025-06-26T16:37:09.005Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team prefers to use TaskScheduler.Current instead of TaskScheduler.Default in Task.Factory.StartNew calls to maintain flexibility for custom schedulers, even though this requires awareness of potential deadlock risks in certain contexts.
test/unit/HttpNtlmAuthenticationServiceTest.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:17-36
Timestamp: 2025-06-26T16:38:49.677Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team initially had concerns about disposing CancellationTokenSource instances before tasks could check cancellation tokens, but they understand that orphaned tasks (those that exceed timeout) won't be impacted by disposed tokens since their results are already ignored by the timeout handler. They prefer proper resource management with using statements for CancellationTokenSource disposal.
src/CommonLib/Processors/ComputerAvailability.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:21-21
Timestamp: 2025-06-26T16:37:09.005Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team prefers to use TaskScheduler.Current instead of TaskScheduler.Default in Task.Factory.StartNew calls to maintain flexibility for custom schedulers, even though this requires awareness of potential deadlock risks in certain contexts.
src/CommonLib/IRegistryKey.cs (2)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:21-21
Timestamp: 2025-06-26T16:37:09.005Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team prefers to use TaskScheduler.Current instead of TaskScheduler.Default in Task.Factory.StartNew calls to maintain flexibility for custom schedulers, even though this requires awareness of potential deadlock risks in certain contexts.
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:17-36
Timestamp: 2025-06-26T16:38:49.677Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team initially had concerns about disposing CancellationTokenSource instances before tasks could check cancellation tokens, but they understand that orphaned tasks (those that exceed timeout) won't be impacted by disposed tokens since their results are already ignored by the timeout handler. They prefer proper resource management with using statements for CancellationTokenSource disposal.
test/unit/ComputerSessionProcessorTest.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:17-36
Timestamp: 2025-06-26T16:38:49.677Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team initially had concerns about disposing CancellationTokenSource instances before tasks could check cancellation tokens, but they understand that orphaned tasks (those that exceed timeout) won't be impacted by disposed tokens since their results are already ignored by the timeout handler. They prefer proper resource management with using statements for CancellationTokenSource disposal.
test/unit/DCLdapProcessorTest.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/LdapConnectionPool.cs:677-677
Timestamp: 2025-06-26T16:59:06.972Z
Learning: In SharpHoundCommonLib's LdapConnectionPool.cs, the team acknowledges that method `GetConnectionForSpecificServerAsync` has misleading naming - it contains "Async" in the name but is actually synchronous and blocks on async code, which they recognize as confusing but may need to live with due to backwards compatibility constraints.
src/CommonLib/ExecutionTimeSampler.cs (2)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:17-36
Timestamp: 2025-06-26T16:38:49.677Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team initially had concerns about disposing CancellationTokenSource instances before tasks could check cancellation tokens, but they understand that orphaned tasks (those that exceed timeout) won't be impacted by disposed tokens since their results are already ignored by the timeout handler. They prefer proper resource management with using statements for CancellationTokenSource disposal.
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:21-21
Timestamp: 2025-06-26T16:37:09.005Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team prefers to use TaskScheduler.Current instead of TaskScheduler.Default in Task.Factory.StartNew calls to maintain flexibility for custom schedulers, even though this requires awareness of potential deadlock risks in certain contexts.
test/unit/AdaptiveTimeoutTest.cs (2)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:17-36
Timestamp: 2025-06-26T16:38:49.677Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team initially had concerns about disposing CancellationTokenSource instances before tasks could check cancellation tokens, but they understand that orphaned tasks (those that exceed timeout) won't be impacted by disposed tokens since their results are already ignored by the timeout handler. They prefer proper resource management with using statements for CancellationTokenSource disposal.
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:21-21
Timestamp: 2025-06-26T16:37:09.005Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team prefers to use TaskScheduler.Current instead of TaskScheduler.Default in Task.Factory.StartNew calls to maintain flexibility for custom schedulers, even though this requires awareness of potential deadlock risks in certain contexts.
src/CommonLib/Processors/CertAbuseProcessor.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/LdapConnectionPool.cs:677-677
Timestamp: 2025-06-26T16:59:06.972Z
Learning: In SharpHoundCommonLib's LdapConnectionPool.cs, the team acknowledges that method `GetConnectionForSpecificServerAsync` has misleading naming - it contains "Async" in the name but is actually synchronous and blocks on async code, which they recognize as confusing but may need to live with due to backwards compatibility constraints.
src/CommonLib/AdaptiveTimeout.cs (2)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:17-36
Timestamp: 2025-06-26T16:38:49.677Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team initially had concerns about disposing CancellationTokenSource instances before tasks could check cancellation tokens, but they understand that orphaned tasks (those that exceed timeout) won't be impacted by disposed tokens since their results are already ignored by the timeout handler. They prefer proper resource management with using statements for CancellationTokenSource disposal.
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:21-21
Timestamp: 2025-06-26T16:37:09.005Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team prefers to use TaskScheduler.Current instead of TaskScheduler.Default in Task.Factory.StartNew calls to maintain flexibility for custom schedulers, even though this requires awareness of potential deadlock risks in certain contexts.
src/CommonLib/Processors/DCLdapProcessor.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/LdapConnectionPool.cs:677-677
Timestamp: 2025-06-26T16:59:06.972Z
Learning: In SharpHoundCommonLib's LdapConnectionPool.cs, the team acknowledges that method `GetConnectionForSpecificServerAsync` has misleading naming - it contains "Async" in the name but is actually synchronous and blocks on async code, which they recognize as confusing but may need to live with due to backwards compatibility constraints.
src/CommonLib/Timeout.cs (2)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:17-36
Timestamp: 2025-06-26T16:38:49.677Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team initially had concerns about disposing CancellationTokenSource instances before tasks could check cancellation tokens, but they understand that orphaned tasks (those that exceed timeout) won't be impacted by disposed tokens since their results are already ignored by the timeout handler. They prefer proper resource management with using statements for CancellationTokenSource disposal.
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:21-21
Timestamp: 2025-06-26T16:37:09.005Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team prefers to use TaskScheduler.Current instead of TaskScheduler.Default in Task.Factory.StartNew calls to maintain flexibility for custom schedulers, even though this requires awareness of potential deadlock risks in certain contexts.
src/CommonLib/Processors/PortScanner.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:21-21
Timestamp: 2025-06-26T16:37:09.005Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team prefers to use TaskScheduler.Current instead of TaskScheduler.Default in Task.Factory.StartNew calls to maintain flexibility for custom schedulers, even though this requires awareness of potential deadlock risks in certain contexts.
src/CommonLib/Ntlm/HttpNtlmAuthenticationService.cs (1)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:17-36
Timestamp: 2025-06-26T16:38:49.677Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team initially had concerns about disposing CancellationTokenSource instances before tasks could check cancellation tokens, but they understand that orphaned tasks (those that exceed timeout) won't be impacted by disposed tokens since their results are already ignored by the timeout handler. They prefer proper resource management with using statements for CancellationTokenSource disposal.
🧬 Code Graph Analysis (4)
test/unit/ComputerAvailabilityTests.cs (2)
src/CommonLib/Processors/PortScanner.cs (4)
  • Task (31-69)
  • PortScanner (9-96)
  • PortScanner (14-16)
  • PortScanner (18-21)
src/SharpHoundRPC/PortScanner/IPortScanner.cs (1)
  • Task (5-5)
src/CommonLib/Processors/ComputerAvailability.cs (1)
src/CommonLib/Processors/PortScanner.cs (3)
  • PortScanner (9-96)
  • PortScanner (14-16)
  • PortScanner (18-21)
src/CommonLib/Processors/ComputerSessionProcessor.cs (3)
src/CommonLib/AdaptiveTimeout.cs (3)
  • AdaptiveTimeout (9-193)
  • AdaptiveTimeout (19-25)
  • TimeSpan (167-175)
src/CommonLib/Logging/Logging.cs (2)
  • Logging (7-20)
  • LogProvider (22-35)
src/CommonLib/OutputTypes/APIResults/SessionAPIResult.cs (1)
  • SessionAPIResult (5-8)
src/CommonLib/Processors/DCLdapProcessor.cs (4)
src/CommonLib/AdaptiveTimeout.cs (2)
  • AdaptiveTimeout (9-193)
  • AdaptiveTimeout (19-25)
src/CommonLib/Logging/Logging.cs (2)
  • Logging (7-20)
  • LogProvider (22-35)
src/CommonLib/OutputTypes/Computer.cs (1)
  • LdapService (33-58)
src/CommonLib/Processors/LocalGroupProcessor.cs (1)
  • SharpHoundRPC (43-52)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (48)
test/unit/SmbProcessorTest.cs (2)

40-43: Event handler signature update looks correct.

The change from async lambda to synchronous lambda returning Task.CompletedTask maintains the same functionality while aligning with the updated asynchronous event handling pattern.


44-44: Timeout parameter removal aligns with adaptive timeout refactoring.

The removal of the explicit timeout parameter from the Scan method call is consistent with the broader refactoring to use adaptive timeout mechanisms internally.

test/unit/ComputerAvailabilityTests.cs (1)

21-21: Mock setup correctly updated for interface change.

The mock setup changes properly reflect the updated IPortScanner.CheckPort method signature which removed the timeout parameter in favor of adaptive timeout handling.

Also applies to: 26-26

test/unit/LocalGroupProcessorTest.cs (2)

32-32: Mock setups correctly updated for adaptive timeout refactoring.

All mock setups for OpenSamServer have been properly updated to expect only the string parameter, removing the timeout parameter to align with the new adaptive timeout mechanism.

Also applies to: 60-60, 165-165, 187-187, 208-208, 229-229, 250-250, 271-271, 294-294, 317-317, 346-346


175-175: Method call updated to remove explicit timeout parameter.

The removal of the timeout parameter from the GetLocalGroups call is consistent with the adaptive timeout refactoring approach.

src/SharpHoundRPC/PortScanner/IPortScanner.cs (1)

5-5: Interface method signature correctly updated for adaptive timeout.

The removal of the timeout parameter from the CheckPort method signature is appropriate as timeout handling is now managed internally by the adaptive timeout mechanism.

src/CommonLib/Processors/ComputerAvailability.cs (3)

19-19: LGTM: Improved timeout configuration approach.

The change to pass maxTimeout to the PortScanner constructor is cleaner than the previous approach of storing timeout separately. This aligns well with the adaptive timeout mechanism that manages timeouts internally.


29-29: LGTM: Consistent timeout parameter handling.

The fallback constructor correctly applies the same timeout configuration pattern as the primary constructor.


101-101: LGTM: Simplified method call aligns with adaptive timeout design.

The removal of the timeout parameter from CheckPort is correct since the PortScanner now manages timeouts internally using the adaptive timeout mechanism.

src/CommonLib/IRegistryKey.cs (3)

3-3: LGTM: Required import for logging functionality.

The Microsoft.Extensions.Logging import is needed for the AdaptiveTimeout logger configuration.


14-14: LGTM: Well-configured adaptive timeout for registry operations.

The AdaptiveTimeout configuration is appropriate for registry operations:

  • 10-second max timeout is reasonable for remote registry connections
  • Sample count of 100 provides good statistical basis
  • Log frequency of 1000 avoids excessive logging
  • Minimum 30 samples before adaptive behavior kicks in is conservative

40-40: LGTM: Proper integration with adaptive timeout mechanism.

The change from the previous timeout mechanism to the adaptive timeout is correctly implemented and maintains the same error handling pattern.

src/CommonLib/LdapUtils.cs (3)

40-42: LGTM: Well-configured adaptive timeouts for network operations.

The AdaptiveTimeout instances are appropriately configured for their respective operations:

  • _requestNetBiosNameAdaptiveTimeout with 1-minute max timeout is suitable for network-based name resolution
  • _callNetWkstaGetInfoAdaptiveTimeout with 2-minute max timeout is appropriate for potentially slow network API calls

The sampling parameters (100 samples, 1000 log frequency, 30 min samples) are consistent with other AdaptiveTimeout uses in the codebase.


719-719: LGTM: Proper integration with adaptive timeout for NetWkstaGetInfo.

The change from the previous timeout mechanism to the adaptive timeout is correctly implemented and maintains the same error handling pattern.


787-787: LGTM: Consistent adaptive timeout integration for NetBIOS name resolution.

The method call correctly uses the adaptive timeout mechanism while preserving the existing error handling and return value patterns.

test/unit/DCLdapProcessorTest.cs (3)

42-45: LGTM: Event handler conversion is correct.

The change from async lambda to synchronous lambda returning Task.CompletedTask is the correct approach for maintaining the async signature while having synchronous handler logic.

Also applies to: 70-73


46-46: LGTM: Method signature simplification aligns with adaptive timeout approach.

Removing the explicit timeout parameter from the Scan method calls correctly reflects the internal shift to adaptive timeout management.

Also applies to: 74-74


89-117: Adaptive timeout behavior is already covered by existing tests

The AdaptiveTimeoutTest.cs suite in test/unit/AdaptiveTimeoutTest.cs includes multiple [Fact] methods that verify:

  • Default timeout when there aren’t enough samples
  • Behavior when adaptive timeout is disabled
  • Dynamic adjustment of the timeout based on varying delays

Since these tests comprehensively cover the adaptive timeout mechanism, the commented-out DCLdapProcessor_CheckScan_Timeout method can safely remain deprecated with no additional timeout tests required.

src/CommonLib/Processors/SmbProcessor.cs (2)

19-25: LGTM: Well-implemented adaptive timeout integration.

The adaptive timeout implementation is correctly integrated:

  • Field properly initialized with reasonable parameters (2-minute max timeout, 100 samples, logging frequency of 1000)
  • Constructor correctly sets MaxTimeoutMs on the ISmbScanner instance
  • Timeout configuration is consistent and appropriate for SMB operations

28-29: LGTM: Clean method signature and adaptive timeout usage.

The simplified method signature and use of ExecuteRPCWithTimeout correctly implements the adaptive timeout pattern while maintaining the same functionality.

src/CommonLib/SMB/SmbScanner.cs (3)

30-31: LGTM: Property rename improves clarity.

Renaming TimeoutMs to MaxTimeoutMs better reflects its role as the maximum timeout ceiling for the adaptive timeout mechanism.


130-130: LGTM: Correct adaptive timeout implementation.

The use of ExecuteWithTimeout with a timeout token parameter correctly implements the adaptive timeout pattern for SMB negotiation operations.


35-38: Fix constructor initialization order issue.

The AdaptiveTimeout is initialized using MaxTimeoutMs before it might be set by the caller. This creates a potential issue where the adaptive timeout uses the default value (2000ms) instead of the intended maximum timeout.

Consider this fix to ensure proper initialization:

public SmbScanner(ILogger log) {
    _log = log ?? Logging.LogProvider.CreateLogger("SmbScanner");
+}

+public void InitializeAdaptiveTimeout() {
    _adaptiveTimeout = new AdaptiveTimeout(maxTimeout: TimeSpan.FromMilliseconds(MaxTimeoutMs), Logging.LogProvider.CreateLogger(nameof(TrySMBNegotiate)), sampleCount: 100, logFrequency: 1000, minSamplesForAdaptiveTimeout: 30);
}

Or initialize the adaptive timeout lazily when first used, or accept the max timeout as a constructor parameter.

Likely an incorrect or invalid review comment.

src/CommonLib/ExecutionTimeSampler.cs (1)

13-28: LGTM: Well-designed sampling infrastructure.

The overall design is solid:

  • Thread-safe queue for concurrent access
  • Proper rolling sample size management
  • IDisposable implementation for cleanup
  • Configurable logging frequency
  • Clean API for different delegate types
src/CommonLib/Processors/CertAbuseProcessor.cs (3)

21-22: LGTM: Proper separation of adaptive timeouts for different operations.

Using separate AdaptiveTimeout instances for GetMachineSid and OpenSamServer operations is the correct approach since these are different RPC operations that may have different performance characteristics. The initialization parameters are consistent and appropriate.

Also applies to: 30-31


371-371: LGTM: Correct async adaptive timeout usage.

The ExecuteRPCWithTimeout call correctly passes the cancellation token to the async GetMachineSid method, maintaining proper async/await patterns.


451-451: LGTM: Correct sync adaptive timeout usage.

The synchronous OpenSamServer operation correctly uses ExecuteRPCWithTimeout with GetAwaiter().GetResult() to maintain the synchronous interface while leveraging the adaptive timeout mechanism.

src/CommonLib/Processors/PortScanner.cs (5)

12-12: LGTM - Adaptive timeout field addition.

The addition of the _adaptiveTimeout field follows the established pattern for integrating adaptive timeout functionality.


14-16: LGTM - Default constructor delegation.

The default constructor properly delegates to the parameterized constructor, maintaining backward compatibility.


18-21: LGTM - Adaptive timeout initialization.

The AdaptiveTimeout initialization uses appropriate parameters:

  • 10-second max timeout (reasonable for port scanning)
  • 100 sample count for good statistical accuracy
  • 1000 log frequency for reasonable logging intervals
  • 30 minimum samples before adaptive behavior kicks in

The logger name "PortScanner" provides clear context for debugging.


31-32: LGTM - Method signature updated correctly.

The CheckPort method signature correctly removes the timeout parameter, delegating timeout management to the adaptive timeout instance.


45-47: LGTM - Adaptive timeout execution implementation.

The replacement of static Timeout.ExecuteWithTimeout with _adaptiveTimeout.ExecuteWithTimeout is correct, and the logging now appropriately uses GetAdaptiveTimeout() to show the actual timeout value being used.

src/CommonLib/Timeout.cs (3)

140-141: LGTM - Cancellation token support added.

The addition of the optional parentToken parameter enables proper cancellation token chaining for adaptive timeout scenarios while maintaining backward compatibility.


156-157: LGTM - Consistent cancellation token integration.

The RPC timeout wrapper correctly forwards the parent cancellation token to the underlying timeout mechanism.


172-173: LGTM - Async RPC timeout wrapper updated.

The async overload of ExecuteRPCWithTimeout is consistently updated to support external cancellation tokens.

test/unit/AdaptiveTimeoutTest.cs (4)

17-25: LGTM - Test for insufficient samples scenario.

The test correctly verifies that when sample count is below the minimum threshold (3), the adaptive timeout returns the maximum timeout value. The test setup and assertion are appropriate.


28-38: LGTM - Test for disabled adaptive timeout.

The test correctly verifies that when adaptive timeout is disabled via the constructor parameter, the maximum timeout is always returned regardless of sample count. The multiple executions ensure sufficient samples are collected.


41-51: LGTM - Test for normal adaptive timeout operation.

The test correctly verifies that with sufficient samples and adaptive mode enabled, the timeout value adapts to be less than the maximum. The varying delays (40ms, 50ms, 60ms) provide realistic execution time variance.


54-67: LGTM - Test for time spike safety valve.

The test correctly simulates the safety valve scenario by first establishing a baseline with fast operations (10ms), then introducing slower operations (100ms) to trigger the safety valve. The assertion verifies that the timeout reverts to the maximum when the safety valve is triggered.

src/CommonLib/Processors/UserRightsAssignmentProcessor.cs (4)

17-19: LGTM - Multiple adaptive timeout instances.

Using separate AdaptiveTimeout instances for different RPC operations (OpenLSAPolicy, GetLocalDomainInformation, GetResolvedPrincipalsWithPrivilege) is the correct approach, as each operation has different timing characteristics.


24-26: LGTM - Adaptive timeout initialization.

The three adaptive timeout instances are properly initialized with:

  • 2-minute max timeout (appropriate for LSA operations)
  • Specific logger names for each operation (good for debugging)
  • Consistent sampling parameters (100 samples, 1000 log frequency, 30 min samples)

The logger names using nameof() provide clear operation context.


55-55: LGTM - Method signature updated correctly.

The removal of the timeout parameter from GetUserRightsAssignments is correct, as timeout management is now handled by the adaptive timeout instances.


56-56: LGTM - RPC calls updated with adaptive timeouts.

All three RPC operations correctly use their respective adaptive timeout instances:

  • Line 56: _openLSAPolicyAdaptiveTimeout for policy opening
  • Line 74: _getLocalDomainInfoAdaptiveTimeout for domain info
  • Line 101: _getResolvedPrincipalWithPriviledgeAdaptiveTimeout for privilege enumeration

The calls properly use ExecuteRPCWithTimeout with the cancellation token parameter.

Also applies to: 74-74, 101-101

src/CommonLib/Processors/ComputerSessionProcessor.cs (5)

25-26: LGTM - Dual adaptive timeout instances.

Using separate AdaptiveTimeout instances for ReadUserSessions and ReadUserSessionsPrivileged is appropriate since these operations have different timing characteristics and privilege requirements.


39-40: LGTM - Adaptive timeout initialization.

Both adaptive timeout instances are properly initialized with:

  • 2-minute max timeout (appropriate for network session enumeration)
  • Specific logger names using nameof() for clear operation context
  • Consistent sampling parameters

The logger names provide clear differentiation between privileged and non-privileged operations.


54-55: LGTM - ReadUserSessions method signature updated.

The removal of the timeout parameter is correct, delegating timeout management to the adaptive timeout instance.


192-193: LGTM - ReadUserSessionsPrivileged method signature updated.

Consistent with the other method, the timeout parameter is correctly removed.


60-84: LGTM - NetAPI calls updated with adaptive timeouts.

Both session enumeration methods correctly use their respective adaptive timeout instances:

  • Line 60: _readUserSessionsAdaptiveTimeout for NetSessionEnum
  • Line 197: _readUserSessionsPriviledgedAdaptiveTimeout for NetWkstaUserEnum

The calls properly use ExecuteNetAPIWithTimeout with the cancellation token parameter, and the timeout token is correctly passed through to the impersonation logic and cancellation checks.

Also applies to: 197-222

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.

Actionable comments posted: 0

🧹 Nitpick comments (3)
test/unit/AdaptiveTimeoutTest.cs (3)

19-19: Add clarity to constructor parameters with named arguments or constants.

The AdaptiveTimeout constructor takes several numeric parameters that aren't immediately clear from the test context. Consider using named arguments or constants to improve readability.

-var adaptiveTimeout = new AdaptiveTimeout(maxTimeout, new TestLogger(_testOutputHelper, Microsoft.Extensions.Logging.LogLevel.Trace), 10, 1000, 3);
+var adaptiveTimeout = new AdaptiveTimeout(
+    maxTimeout: maxTimeout, 
+    logger: new TestLogger(_testOutputHelper, Microsoft.Extensions.Logging.LogLevel.Trace), 
+    sampleSize: 10, 
+    timeoutCalculationMultiplier: 1000, 
+    minimumSamples: 3);

Also applies to: 30-30, 43-43, 57-57


17-25: Consider adding more comprehensive edge case testing.

The current tests cover the main scenarios well, but consider adding tests for:

  • Null or invalid parameters
  • Zero or negative timeouts
  • Boundary conditions (exactly minimum samples)
  • Concurrent execution scenarios
  • Exception handling during execution

Example additional test cases:

[Fact]
public void AdaptiveTimeout_Constructor_NullLogger_ThrowsException() {
    Assert.Throws<ArgumentNullException>(() => 
        new AdaptiveTimeout(TimeSpan.FromSeconds(1), null, 10, 1000, 3));
}

[Fact]
public void AdaptiveTimeout_Constructor_ZeroTimeout_ThrowsException() {
    Assert.Throws<ArgumentException>(() => 
        new AdaptiveTimeout(TimeSpan.Zero, new TestLogger(_testOutputHelper, LogLevel.Trace), 10, 1000, 3));
}

Also applies to: 28-38, 41-51, 54-67


17-17: Consider more descriptive test method names.

The current test names are functional but could be more descriptive about the expected behavior.

Consider renaming for better clarity:

-public async Task AdaptiveTimeout_GetAdaptiveTimeout_NotEnoughSamplesAsync()
+public async Task AdaptiveTimeout_ReturnsMaxTimeout_WhenInsufficientSamples()

-public async Task AdaptiveTimeout_GetAdaptiveTimeout_AdaptiveDisabled()
+public async Task AdaptiveTimeout_ReturnsMaxTimeout_WhenAdaptiveDisabled()

-public async Task AdaptiveTimeout_GetAdaptiveTimeout()
+public async Task AdaptiveTimeout_ReturnsReducedTimeout_WhenSufficientSamples()

-public async Task AdaptiveTimeout_GetAdaptiveTimeout_TimeSpikeSafetyValve()
+public async Task AdaptiveTimeout_ReturnsMaxTimeout_WhenSafetyValveTriggered()

Also applies to: 28-28, 41-41, 54-54

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5bda0ff and 7694fd6.

📒 Files selected for processing (1)
  • test/unit/AdaptiveTimeoutTest.cs (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#222
File: src/CommonLib/ExecutionTimeSampler.cs:35-43
Timestamp: 2025-07-11T20:15:16.164Z
Learning: In SharpHoundCommon ExecutionTimeSampler statistical methods, the user prefers to keep simple implementations without thread safety snapshots because precise values aren't needed for analysis purposes - they're comfortable with potentially imprecise values from concurrent access.
test/unit/AdaptiveTimeoutTest.cs (3)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:17-36
Timestamp: 2025-06-26T16:38:49.677Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team initially had concerns about disposing CancellationTokenSource instances before tasks could check cancellation tokens, but they understand that orphaned tasks (those that exceed timeout) won't be impacted by disposed tokens since their results are already ignored by the timeout handler. They prefer proper resource management with using statements for CancellationTokenSource disposal.
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:21-21
Timestamp: 2025-06-26T16:37:09.005Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team prefers to use TaskScheduler.Current instead of TaskScheduler.Default in Task.Factory.StartNew calls to maintain flexibility for custom schedulers, even though this requires awareness of potential deadlock risks in certain contexts.
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#222
File: src/CommonLib/ExecutionTimeSampler.cs:35-43
Timestamp: 2025-07-11T20:15:16.164Z
Learning: In SharpHoundCommon ExecutionTimeSampler statistical methods, the user prefers to keep simple implementations without thread safety snapshots because precise values aren't needed for analysis purposes - they're comfortable with potentially imprecise values from concurrent access.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
test/unit/AdaptiveTimeoutTest.cs (2)

9-14: LGTM! Clean test class structure.

The test class follows proper xUnit patterns with constructor injection for test output handling.


21-21: Consider timing precision concerns in tests.

The tests rely on Task.Delay operations which may not be perfectly precise, potentially leading to flaky tests in CI environments or under load. Consider adding tolerance margins or using more deterministic timing mechanisms if tests become unstable.

Monitor these tests for flakiness in CI environments. If timing precision becomes an issue, consider:

  1. Adding tolerance margins to assertions
  2. Using deterministic timing mechanisms
  3. Mocking the timing dependencies

Also applies to: 32-34, 45-47, 59-63

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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/CommonLib/LdapConnectionPool.cs (2)

61-64: Consider making timeout configurations customizable.

The adaptive timeout initialization is correct, but all instances use identical configuration values. Different LDAP operations might have different performance characteristics that could benefit from tailored configurations.

Consider extracting these configuration values to the LdapConfig class to allow customization per operation type:

-_queryAdaptiveTimeout = new AdaptiveTimeout(maxTimeout: TimeSpan.FromMinutes(2), Logging.LogProvider.CreateLogger("LdapQuery"), sampleCount: 100, logFrequency: 1000, minSamplesForAdaptiveTimeout: 30);
+_queryAdaptiveTimeout = new AdaptiveTimeout(
+    maxTimeout: config.QueryMaxTimeout ?? TimeSpan.FromMinutes(2), 
+    Logging.LogProvider.CreateLogger("LdapQuery"), 
+    sampleCount: config.QuerySampleCount ?? 100, 
+    logFrequency: config.QueryLogFrequency ?? 1000, 
+    minSamplesForAdaptiveTimeout: config.QueryMinSamples ?? 30);

176-185: Good addition of timeout retry logic.

Treating timeouts similarly to busy errors with exponential backoff is a sensible approach. However, the log messages could be more precise.

Consider making the log messages more specific about the timeout nature:

-_log.LogDebug("Query - Timeout: Executing busy backoff for query {Info} (Attempt {Count})",
+_log.LogDebug("Query - Timeout occurred, executing exponential backoff for query {Info} (Attempt {Count})",

Also applies to: 347-356, 508-517

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8de6101 and 76f90db.

📒 Files selected for processing (1)
  • src/CommonLib/LdapConnectionPool.cs (11 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#222
File: src/CommonLib/ExecutionTimeSampler.cs:35-43
Timestamp: 2025-07-11T20:15:16.164Z
Learning: In SharpHoundCommon ExecutionTimeSampler statistical methods, the user prefers to keep simple implementations without thread safety snapshots because precise values aren't needed for analysis purposes - they're comfortable with potentially imprecise values from concurrent access.
src/CommonLib/LdapConnectionPool.cs (2)
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/LdapConnectionPool.cs:677-677
Timestamp: 2025-06-26T16:59:06.972Z
Learning: In SharpHoundCommonLib's LdapConnectionPool.cs, the team acknowledges that method `GetConnectionForSpecificServerAsync` has misleading naming - it contains "Async" in the name but is actually synchronous and blocks on async code, which they recognize as confusing but may need to live with due to backwards compatibility constraints.
Learnt from: definitelynotagoblin
PR: SpecterOps/SharpHoundCommon#217
File: src/CommonLib/Timeout.cs:21-21
Timestamp: 2025-06-26T16:37:09.005Z
Learning: In SharpHoundCommonLib's Timeout.cs, the team prefers to use TaskScheduler.Current instead of TaskScheduler.Default in Task.Factory.StartNew calls to maintain flexibility for custom schedulers, even though this requires awareness of potential deadlock risks in certain contexts.
🧬 Code Graph Analysis (1)
src/CommonLib/LdapConnectionPool.cs (3)
src/CommonLib/Logging/Logging.cs (2)
  • Logging (7-20)
  • LogProvider (22-35)
src/CommonLib/LdapQueryParameters.cs (1)
  • GetQueryInfo (43-46)
src/CommonLib/Ntlm/LdapNative.cs (1)
  • LdapConnection (29-253)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
src/CommonLib/LdapConnectionPool.cs (2)

30-33: LGTM! Well-structured adaptive timeout fields.

The four distinct adaptive timeout instances appropriately separate different LDAP operation types, allowing each to have its own timeout behavior based on historical performance.


111-111: Consistent migration to adaptive timeouts.

All SendRequestAsync calls have been properly replaced with SendRequestWithTimeout using the appropriate adaptive timeout instance for each operation type.

Also applies to: 276-276, 499-499, 982-982

…current timeout on time spike safety valve event
Copy link
Contributor

@mykeelium mykeelium left a comment

Choose a reason for hiding this comment

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

This looks like an awesome change and extremely well done for how large it is! This will be great to get in. A few comment and questions. Since some interfaces changed should this also be a minor version bump?

@definitelynotagoblin
Copy link
Contributor Author

Honestly I've been on the fence about that too.
I may have been overzealous in removing the now-unused timeout params from the public functions.
I'm inclined to say yes just cover it under a minor version bump,
But I'll have to confirm above if we're okay with that.

@definitelynotagoblin definitelynotagoblin merged commit f27ae9a into v4 Jul 15, 2025
3 checks passed
@definitelynotagoblin definitelynotagoblin deleted the adaptive-timeouts branch July 15, 2025 20:21
@github-actions github-actions bot locked and limited conversation to collaborators Jul 15, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants