Skip to content

chore: SHC -dev package workflows gracefully handle -rc packages BED-7878#297

Open
lrfalslev wants to merge 11 commits intov4from
lfalslev/bed-7878
Open

chore: SHC -dev package workflows gracefully handle -rc packages BED-7878#297
lrfalslev wants to merge 11 commits intov4from
lfalslev/bed-7878

Conversation

@lrfalslev
Copy link
Copy Markdown
Contributor

@lrfalslev lrfalslev commented Apr 15, 2026

Description

Rewrite SHC -dev publishing workflow and SH/SHE csprojs to consume -dev packages, while gracefully handling -rc package versions.
Upgrade .net and testing package versions.
Update readmes.

Motivation and Context

This PR addresses: BED-7878

How Has This Been Tested?

See Manual Testing Instructions on ticket.

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:

Summary by CodeRabbit

Release Notes

  • Chores

    • Updated CI/CD workflows to use .NET SDK 10.0.x for building and testing
    • Migrated test projects to target .NET 10.0 framework
    • Upgraded testing and code coverage tool dependencies to current versions
  • Tests

    • Removed deprecated smoke tests from test suite
    • Refined test assertions and timing validation logic

@lrfalslev lrfalslev self-assigned this Apr 15, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 84ef6a08-96c6-4ca3-96e9-6310f81b112b

📥 Commits

Reviewing files that changed from the base of the PR and between b15101f and 16f9a64.

📒 Files selected for processing (1)
  • .github/workflows/publish-dev-package.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/publish-dev-package.yml

Walkthrough

The project is upgraded to .NET 10.0, with CI/CD workflows updated to the new SDK version. Test projects and dependencies are modernized, including framework retargeting, dependency version updates, removal of the SmokeTest class, and adjustments to certificate loading and timeout test logic.

Changes

Cohort / File(s) Summary
CI/CD Workflow SDK Updates
.github/workflows/build-and-test.yml, .github/workflows/publish-dev-package.yml, .github/workflows/publish.yml
Updated .NET SDK from 8.0.x to 10.0.x across workflows. Simplified publish workflow to target only 10.0.x instead of multiple SDK versions.
Test Project Configuration
RPCTest/RPCTest.csproj, test/unit/CommonLibTest.csproj
Retargeted projects from net8.0 to net10.0, added <IsTestProject>true</IsTestProject> property. Upgraded test framework packages: Microsoft.NET.Test.Sdk (16.7.1 → 18.4.0), xunit (2.4.1 → 2.9.3), xunit.runner.visualstudio (2.4.1/2.4.3 → 3.1.5). Coverage packages updated: coverlet.msbuild/coverlet.collector (3.0.3 → 8.0.1), ReportGenerator (4.8.9 → 5.5.5). Minor dependency updates: Newtonsoft.Json (13.0.3 → 13.0.4). Removed Xbehave dependency.
Test Code Modernization
test/unit/Facades/MockDirectoryObject.cs, test/unit/ACLProcessorTest.cs
Updated certificate loading from new X509Certificate2(x) to X509CertificateLoader.LoadCertificate(x). Adopted C# collection expressions ([] instead of Array.Empty<T>()). Added namespace alias for AsyncEnumerable.
Test Removal and Adjustments
test/unit/SmokeTest.cs, test/unit/AdaptiveTimeoutTest.cs, test/unit/TimeoutTests.cs
Removed entire SmokeTest class (52 lines deleted). Modified timeout tests: replaced upper-bound latency assertions with non-negativity checks; adjusted workload in AdaptiveTimeout_GetAdaptiveTimeout from delayed tasks to Task.CompletedTask. Extended sleep/wait durations in TimeoutTests from 500/600ms to 1000/1200ms.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A hop toward ten, the future's gleaming bright,
Old tests fade away, new frameworks take flight,
Certificates loaded with modern finesse,
Collection expressions, less code, cleaner mess,
The warren rejoices—the upgrade's success!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 describes the main change: updating SHC -dev package workflows to handle -rc packages while upgrading .NET and testing versions.
Description check ✅ Passed The description follows the template structure and includes all key sections: Description, Motivation/Context with ticket reference, testing approach, Types of changes, and completed Checklist.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lfalslev/bed-7878

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
Copy Markdown

@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)
.github/workflows/publish-dev-package.yml (1)

28-28: Consider keeping a single mutable -dev version if that’s still the team contract.

Timestamped -dev versions create many artifacts; if downstream expects one “current state” dev package, this moves away from that model.

Alternative aligned with single-current-dev strategy
- "dev_version=$base_version-dev.$date_stamp" >> $env:GITHUB_OUTPUT
+ "dev_version=$base_version-dev" >> $env:GITHUB_OUTPUT

And in publish step:

- sleet push ./pkgs
+ sleet push --force ./pkgs

Based on learnings: In the SpecterOps/SharpHoundCommon repository, the team prefers using sleet push --force to overwrite git-dev packages rather than creating unique versions with commit SHAs, as they want a single "current state" package for downstream consumers.

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

In @.github/workflows/publish-dev-package.yml at line 28, The workflow currently
builds a timestamped dev release via the env variable dev_version (using
base_version and date_stamp); change it to emit a single mutable dev version
instead (e.g., set dev_version to base_version + "-dev" without the date_stamp)
and update the downstream publish step to use the overwrite/force semantics your
team uses (for example, switch to sleet push --force or the equivalent CI
publish flag) so the pipeline produces one current-state dev artifact rather
than timestamped artifacts.
test/unit/Facades/MockDirectoryObject.cs (1)

127-134: Align mock cert parsing behavior with production facade.

The mock currently fails the whole call if any certificate byte array is invalid. Production (src/CommonLib/DirectoryObjects/DirectoryEntryWrapper.cs, Lines 109-133) skips bad cert entries and returns successfully, so tests can become stricter than runtime behavior.

Proposed alignment
 public bool TryGetCertificateArrayProperty(string propertyName, out X509Certificate2[] value) {
     if (!TryGetByteArrayProperty(propertyName, out var b)) {
-        value = [];
+        value = [];
         return false;
     }
 
-    value = b.Select(X509CertificateLoader.LoadCertificate).ToArray();
+    var certs = new List<X509Certificate2>(b.Length);
+    foreach (var certBytes in b) {
+        try {
+            certs.Add(X509CertificateLoader.LoadCertificate(certBytes));
+        }
+        catch {
+            // mirror production behavior: skip invalid certs
+        }
+    }
+    value = certs.ToArray();
     return true;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/unit/Facades/MockDirectoryObject.cs` around lines 127 - 134,
TryGetCertificateArrayProperty currently fails the whole call when any
certificate byte array is invalid; change it to mirror production
DirectoryEntryWrapper behavior by calling TryGetByteArrayProperty(propertyName,
out var b) and, if true, iterate b, attempt
X509CertificateLoader.LoadCertificate for each entry inside a try/catch, collect
only successfully loaded X509Certificate2 instances (skip entries that throw or
are invalid), set value to that collected array (empty array if none succeeded)
and return true; if TryGetByteArrayProperty returns false, set value to an empty
array and return false.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/publish-dev-package.yml:
- Around line 6-7: The workflow trigger currently only includes the feature
branch "lfalslev/bed-7878" and has commented out "v4", which prevents runs on
regular v4 pushes; update the triggers in the publish-dev-package workflow to
include the "v4" branch (restore or add "v4" alongside "lfalslev/bed-7878") so
dev package publishing runs for both the feature branch and normal v4 pushes.

---

Nitpick comments:
In @.github/workflows/publish-dev-package.yml:
- Line 28: The workflow currently builds a timestamped dev release via the env
variable dev_version (using base_version and date_stamp); change it to emit a
single mutable dev version instead (e.g., set dev_version to base_version +
"-dev" without the date_stamp) and update the downstream publish step to use the
overwrite/force semantics your team uses (for example, switch to sleet push
--force or the equivalent CI publish flag) so the pipeline produces one
current-state dev artifact rather than timestamped artifacts.

In `@test/unit/Facades/MockDirectoryObject.cs`:
- Around line 127-134: TryGetCertificateArrayProperty currently fails the whole
call when any certificate byte array is invalid; change it to mirror production
DirectoryEntryWrapper behavior by calling TryGetByteArrayProperty(propertyName,
out var b) and, if true, iterate b, attempt
X509CertificateLoader.LoadCertificate for each entry inside a try/catch, collect
only successfully loaded X509Certificate2 instances (skip entries that throw or
are invalid), set value to that collected array (empty array if none succeeded)
and return true; if TryGetByteArrayProperty returns false, set value to an empty
array and return false.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f25eb029-e1a8-4d5f-b115-8ba6b073e110

📥 Commits

Reviewing files that changed from the base of the PR and between dafa641 and c706077.

📒 Files selected for processing (8)
  • .github/workflows/build-and-test.yml
  • .github/workflows/publish-dev-package.yml
  • .github/workflows/publish.yml
  • RPCTest/RPCTest.csproj
  • test/unit/ACLProcessorTest.cs
  • test/unit/CommonLibTest.csproj
  • test/unit/Facades/MockDirectoryObject.cs
  • test/unit/SmokeTest.cs
💤 Files with no reviewable changes (1)
  • test/unit/SmokeTest.cs

Comment thread .github/workflows/publish-dev-package.yml Outdated
Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/CommonLib/Processors/ACLProcessor.cs`:
- Line 45: The public constructor ACLProcessor(ILdapUtils utils, string
TEST_BREAKING_CHANGE, ILogger log = null) includes an unused required parameter
TEST_BREAKING_CHANGE causing an unnecessary breaking change; remove that
parameter from the constructor signature (leave ACLProcessor(ILdapUtils utils,
ILogger log = null)), update any internal constructor body references if
present, and adjust all call sites to stop passing TEST_BREAKING_CHANGE (or
overload if backwards compatibility is required), and update any related XML
doc/comments for the constructor.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f20c82c2-a0b5-47ef-b5d1-70eaedeb89a6

📥 Commits

Reviewing files that changed from the base of the PR and between c706077 and fee02ca.

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

Comment thread src/CommonLib/Processors/ACLProcessor.cs Outdated
Copy link
Copy Markdown

@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

♻️ Duplicate comments (1)
.github/workflows/publish-dev-package.yml (1)

6-7: ⚠️ Potential issue | 🟠 Major

Restore v4 in the push trigger before merge.

Line 6 scopes runs to a feature branch, and Line 7 comments out v4; once merged, normal v4 pushes won’t publish dev packages.

Suggested fix
 on:
   push:
     branches:
-      - "lfalslev/bed-7878"
-#      - "v4"
+      - "v4"
+      # - "lfalslev/bed-7878" # keep temporarily if still needed
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/publish-dev-package.yml around lines 6 - 7, Restore the
"v4" branch entry in the workflow push trigger so dev package publishing runs on
v4 pushes again: in the push.branches list (where "lfalslev/bed-7878" was added
and "v4" is commented out), uncomment or re-add the "v4" entry and keep the
feature branch entry if needed so the push trigger includes both "v4" and
"lfalslev/bed-7878".
🧹 Nitpick comments (2)
test/unit/AdaptiveTimeoutTest.cs (1)

82-84: Verify that testing with Task.CompletedTask still exercises the adaptive timeout logic meaningfully.

Switching from Task.Delay(40/50/60) to Task.CompletedTask eliminates timing variability but also means observed latencies will be near-zero. The test still asserts adaptiveTimeoutResult < maxTimeout at line 87, which should pass since the adaptive calculation should produce a small timeout for fast-completing tasks.

If the intent is purely to stabilize the test, this is acceptable. However, consider whether a separate integration-style test with real delays (perhaps in a non-CI context) would be valuable to ensure the adaptive logic works correctly with actual latency variance.

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

In `@test/unit/AdaptiveTimeoutTest.cs` around lines 82 - 84, The test in
AdaptiveTimeoutTest now calls adaptiveTimeout.ExecuteWithTimeout with
Task.CompletedTask for LatencyObservation1/2/3 which yields near-zero observed
latencies and may not meaningfully exercise the adaptive timeout algorithm;
update the unit test to either (a) restore small deterministic delays (e.g.
Task.Delay(40/50/60) or similar) when calling adaptiveTimeout.ExecuteWithTimeout
so LatencyObservation1/2/3 produce non-zero latency samples, or (b) keep
Task.CompletedTask but add a separate integration-style test that uses real
Task.Delay to validate adaptive behavior; ensure the assertions around
adaptiveTimeoutResult < maxTimeout still run against the variant that provides
realistic latency samples and reference the AdaptiveTimeoutTest class and
adaptiveTimeout.ExecuteWithTimeout calls for changes.
test/unit/TimeoutTests.cs (1)

153-165: Align async and sync timeout test values for consistency.

The async ExecuteWithTimeout_Task_Timeout_Cancel (lines 154-165) and ExecuteWithTimeout_Task_T_Timeout_Cancel (lines 214-226) tests use 500ms/600ms timeouts, while the sync equivalents use 1000ms/1200ms. Since both test the same cancellation behavior, consider aligning these values across all variants for consistency and to avoid future confusion.

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

In `@test/unit/TimeoutTests.cs` around lines 153 - 165, The async test
ExecuteWithTimeout_Task_Timeout_Cancel uses 100ms/500ms/600ms split that
mismatches the sync tests; update the timeout and delays in
ExecuteWithTimeout_Task_Timeout_Cancel (the timeout variable and Task.Delay
calls inside func and after ExecuteWithTimeout) to match the sync equivalents
(use 1000ms for the timeout, 1000ms/1200ms delays as in the sync variants) so
all ExecuteWithTimeout_*_Timeout_Cancel tests use consistent timing and verify
the same cancellation behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/publish-dev-package.yml:
- Line 13: Remove the invalid dependency "needs: build-and-test" from the
workflow because no job named build-and-test exists in this file; locate the
jobs block where the line "needs: build-and-test" appears and either delete that
needs entry or replace it with the correct existing job name(s) in this workflow
so the job dependency references only jobs defined in the same jobs: block.

---

Duplicate comments:
In @.github/workflows/publish-dev-package.yml:
- Around line 6-7: Restore the "v4" branch entry in the workflow push trigger so
dev package publishing runs on v4 pushes again: in the push.branches list (where
"lfalslev/bed-7878" was added and "v4" is commented out), uncomment or re-add
the "v4" entry and keep the feature branch entry if needed so the push trigger
includes both "v4" and "lfalslev/bed-7878".

---

Nitpick comments:
In `@test/unit/AdaptiveTimeoutTest.cs`:
- Around line 82-84: The test in AdaptiveTimeoutTest now calls
adaptiveTimeout.ExecuteWithTimeout with Task.CompletedTask for
LatencyObservation1/2/3 which yields near-zero observed latencies and may not
meaningfully exercise the adaptive timeout algorithm; update the unit test to
either (a) restore small deterministic delays (e.g. Task.Delay(40/50/60) or
similar) when calling adaptiveTimeout.ExecuteWithTimeout so
LatencyObservation1/2/3 produce non-zero latency samples, or (b) keep
Task.CompletedTask but add a separate integration-style test that uses real
Task.Delay to validate adaptive behavior; ensure the assertions around
adaptiveTimeoutResult < maxTimeout still run against the variant that provides
realistic latency samples and reference the AdaptiveTimeoutTest class and
adaptiveTimeout.ExecuteWithTimeout calls for changes.

In `@test/unit/TimeoutTests.cs`:
- Around line 153-165: The async test ExecuteWithTimeout_Task_Timeout_Cancel
uses 100ms/500ms/600ms split that mismatches the sync tests; update the timeout
and delays in ExecuteWithTimeout_Task_Timeout_Cancel (the timeout variable and
Task.Delay calls inside func and after ExecuteWithTimeout) to match the sync
equivalents (use 1000ms for the timeout, 1000ms/1200ms delays as in the sync
variants) so all ExecuteWithTimeout_*_Timeout_Cancel tests use consistent timing
and verify the same cancellation behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 20053fdf-69bf-4f4a-ba21-1327284d9b80

📥 Commits

Reviewing files that changed from the base of the PR and between 9bad034 and b15101f.

📒 Files selected for processing (4)
  • .github/workflows/publish-dev-package.yml
  • test/unit/AdaptiveTimeoutTest.cs
  • test/unit/CommonLibTest.csproj
  • test/unit/TimeoutTests.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/unit/CommonLibTest.csproj

Comment thread .github/workflows/publish-dev-package.yml Outdated
Copy link
Copy Markdown

@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.

♻️ Duplicate comments (1)
src/CommonLib/Processors/ACLProcessor.cs (1)

45-49: ⚠️ Potential issue | 🔴 Critical

Revert the unused required constructor parameter to avoid a breaking compile change.

Line 45 introduces BREAKING_COMMON_CHANGE_TEST as a required argument, but it is unused in Lines 47-49. This creates a no-op API break and currently invalidates existing constructor calls (e.g., test/unit/ACLProcessorTest.cs Line 47 and Line 78; snippet metadata indicates many more). Please remove it (or make it optional with a default) to preserve compatibility.

💡 Proposed fix
-        public ACLProcessor(ILdapUtils utils, string BREAKING_COMMON_CHANGE_TEST, ILogger log = null)
+        public ACLProcessor(ILdapUtils utils, ILogger log = null)
         {
             _utils = utils;
             _log = log ?? Logging.LogProvider.CreateLogger("ACLProc");
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/CommonLib/Processors/ACLProcessor.cs` around lines 45 - 49, The
ACLProcessor constructor signature was changed to require a new unused parameter
BREAKING_COMMON_CHANGE_TEST which breaks existing callers; restore compatibility
by removing the BREAKING_COMMON_CHANGE_TEST parameter from the ACLProcessor
constructor (or make it optional with a default value) so existing
instantiations compile, keeping the body that assigns _utils and _log unchanged
(see the ACLProcessor constructor and fields _utils, _log).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/CommonLib/Processors/ACLProcessor.cs`:
- Around line 45-49: The ACLProcessor constructor signature was changed to
require a new unused parameter BREAKING_COMMON_CHANGE_TEST which breaks existing
callers; restore compatibility by removing the BREAKING_COMMON_CHANGE_TEST
parameter from the ACLProcessor constructor (or make it optional with a default
value) so existing instantiations compile, keeping the body that assigns _utils
and _log unchanged (see the ACLProcessor constructor and fields _utils, _log).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f395392e-408e-4487-b278-4b36409ff30d

📥 Commits

Reviewing files that changed from the base of the PR and between b15101f and 9c103f4.

📒 Files selected for processing (2)
  • .github/workflows/publish-dev-package.yml
  • src/CommonLib/Processors/ACLProcessor.cs
✅ Files skipped from review due to trivial changes (1)
  • .github/workflows/publish-dev-package.yml

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant