Skip to content

fix: GetLocalGroups RPC response time too variant for adaptive timeouts#277

Open
definitelynotagoblin wants to merge 2 commits intov4from
anemeth/rpc-get-group-members-timeout-fix
Open

fix: GetLocalGroups RPC response time too variant for adaptive timeouts#277
definitelynotagoblin wants to merge 2 commits intov4from
anemeth/rpc-get-group-members-timeout-fix

Conversation

@definitelynotagoblin
Copy link
Contributor

@definitelynotagoblin definitelynotagoblin commented Mar 4, 2026

Description

GetLocalGroups for RPC is too inconsistent in payload and response time to extract much value from adaptive timeout logic, and is causing data loss besides. Switching to static timeouts.

Motivation and Context

https://specterops.atlassian.net/browse/BED-7153

How Has This Been Tested?

Screenshots (if appropriate):

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

  • Chores
    • Optimized timeout handling for group member operations to use fixed timeouts, improving consistency in error handling flows.

…se time to extract much value from adaptive timeout logic, and is causing data loss besides. Going to switch to static timeouts
@definitelynotagoblin definitelynotagoblin self-assigned this Mar 4, 2026
@definitelynotagoblin definitelynotagoblin added the bug Something isn't working label Mar 4, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2026

Walkthrough

A timeout mechanism in LocalGroupProcessor.cs was refactored, replacing an adaptive timeout instance with a fixed 2-minute timeout wrapper for RPC GetMembers calls.

Changes

Cohort / File(s) Summary
Timeout Mechanism Update
src/CommonLib/Processors/LocalGroupProcessor.cs
Removed _getMembersAdaptiveTimeout field and replaced its ExecuteRPCWithTimeout usage with a fixed Timeout.ExecuteRPCWithTimeout(TimeSpan.FromMinutes(2), ...) call for GetMembers RPC operations.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A timeout once adaptive, now fixed and quite true,
No more shall we wait for uncertainty's brew,
Two minutes we promise, no more, no less dear,
The GetMembers call now runs crystal clear!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: replacing adaptive timeouts with fixed timeouts for the GetLocalGroups RPC call due to response time inconsistency.
Description check ✅ Passed The description covers the key required sections: it explains what changed (switching from adaptive to static timeouts), why (inconsistent response times causing data loss), includes issue link and testing confirmation, and marks the appropriate type of change checkbox.

✏️ 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 anemeth/rpc-get-group-members-timeout-fix

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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 (1)
src/CommonLib/Processors/LocalGroupProcessor.cs (1)

215-232: ⚠️ Potential issue | 🟠 Major

IsTimeout check is now dead code with static Timeout.ExecuteRPCWithTimeout.

The Timeout.ExecuteRPCWithTimeout method (per context snippet 2) returns SharpHoundRPC.Result<T>.Fail(result.Error) on timeout, which only sets the Error string property. The IsTimeout property is never set to true by this code path—Result<T>.Fail(string) only initializes Error.

This means the check at lines 229-231 will never trigger, making it dead code:

if (getMembersResult.IsTimeout) {
    yield break;
}

Either:

  1. Remove the dead IsTimeout check since early termination on this specific timeout may not be desired (given the PR's goal to avoid data loss from premature timeouts), or
  2. Update Timeout.ExecuteRPCWithTimeout to set IsTimeout = true when the failure is due to timeout.
Option 1: Remove the dead code
                        ret.Collected = false;
                        ret.FailureReason = $"SamGetMembersInAlias failed with status {getMembersResult.SError}";
                        yield return ret;
-                        if (getMembersResult.IsTimeout) {
-                            yield break;
-                        }
                        continue;
Option 2: Fix Timeout.ExecuteRPCWithTimeout to set IsTimeout

In src/CommonLib/Timeout.cs, around line 156-162:

 public static async Task<SharpHoundRPC.Result<T>> ExecuteRPCWithTimeout<T>(TimeSpan timeout, Func<CancellationToken, SharpHoundRPC.Result<T>> func, CancellationToken parentToken = default) {
     var result = await ExecuteWithTimeout(timeout, func, parentToken);
     if (result.IsSuccess)
         return result.Value;
-    else
-        return SharpHoundRPC.Result<T>.Fail(result.Error);
+    else {
+        var failResult = SharpHoundRPC.Result<T>.Fail(result.Error);
+        failResult.IsTimeout = result.Error?.Contains("Timeout after") == true;
+        return failResult;
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/CommonLib/Processors/LocalGroupProcessor.cs` around lines 215 - 232, The
IsTimeout branch is dead because Timeout.ExecuteRPCWithTimeout returns a failed
Result without setting IsTimeout; remove the unreachable check and its yield
break to avoid misleading code: delete the `if (getMembersResult.IsTimeout) {
yield break; }` block in LocalGroupProcessor where `getMembersResult` is handled
(inside the GetMembers RPC handling after Timeout.ExecuteRPCWithTimeout) and
ensure the surrounding logic still continues/returns as intended
(ret.Collected=false, FailureReason set, yield return ret, continue).
🤖 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/LocalGroupProcessor.cs`:
- Around line 215-232: The IsTimeout branch is dead because
Timeout.ExecuteRPCWithTimeout returns a failed Result without setting IsTimeout;
remove the unreachable check and its yield break to avoid misleading code:
delete the `if (getMembersResult.IsTimeout) { yield break; }` block in
LocalGroupProcessor where `getMembersResult` is handled (inside the GetMembers
RPC handling after Timeout.ExecuteRPCWithTimeout) and ensure the surrounding
logic still continues/returns as intended (ret.Collected=false, FailureReason
set, yield return ret, continue).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0faced32-2219-43c0-9e97-5b8ddfe88005

📥 Commits

Reviewing files that changed from the base of the PR and between 9ea2281 and 6e16de7.

📒 Files selected for processing (1)
  • src/CommonLib/Processors/LocalGroupProcessor.cs

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.

1 participant