Skip to content

Update/20260722 record dtos - #36

Merged
bitai-cs merged 7 commits into
mainfrom
update/20260722-record-dtos
Oct 1, 2026
Merged

bitai-cs merged 7 commits into
mainfrom
update/20260722-record-dtos

Conversation

@bitai-cs

@bitai-cs bitai-cs commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Summary by Sourcery

Modernize Active Directory DTOs and align LDAP search, account management, mock data, and tests with the updated Bitai directory model.

New Features:

  • Add immutable record-based Active Directory user DTOs with bulk initialization, validation, and secure cloning.
  • Add support for searching parent entries from existing LDAP entries and improve mock LDAP data seeding for the Bitai domain structure.

Bug Fixes:

  • Require callers to provide a user distinguished name when creating Active Directory accounts instead of generating it implicitly.
  • Align mock LDAP attributes, filters, domains, relationships, and test fixtures with the updated directory schema and Bitai domain names.
  • Improve authentication and LDAP search error messages with clearer contextual information.

Enhancements:

  • Update LDAP account management and search flows to use the revised DTO and parent-entry behavior.
  • Add string representation support for search limits and refresh mock connection initialization and data setup.

Tests:

  • Update account-management and mock LDAP tests for explicit distinguished names, revised attributes, and the Bitai search base.

Chores:

  • Apply broad formatting and cleanup updates across LDAP adapters and management classes.

@sourcery-ai

sourcery-ai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer's Guide

The PR migrates the AD user DTO to an immutable record, makes account creation require an explicit distinguished name, adds reusable parent-entry search and clearer error messages, and comprehensively realigns the mock LDAP dataset and tests with the Bitai AD namespace and Name/containerDN attribute model.

Sequence diagram for explicit AD account creation

sequenceDiagram
    participant Caller
    participant AccountManager
    participant Searcher
    participant LDAP

    Caller->>AccountManager: CreateUserAccountForMsAD(userAccount)
    AccountManager->>AccountManager: validate DistinguishedNameOfContainer
    AccountManager->>AccountManager: validate DistinguishedName
    AccountManager->>Searcher: SearchEntriesAsync(distinguishedNameFilter)
    Searcher->>LDAP: SearchAsync
    LDAP-->>Searcher: matching entries
    Searcher-->>AccountManager: search result
    AccountManager->>LDAP: AddEntryAsync(DistinguishedName)
    LDAP-->>AccountManager: creation result
    AccountManager-->>Caller: LDAPCreateMsADUserAccountResult
Loading

Sequence diagram for reusable parent-entry search

sequenceDiagram
    participant Caller
    participant Searcher
    participant LDAP

    Caller->>Searcher: SearchParentEntriesAsync(searchFilter, requiredEntryAttributes)
    Searcher->>Searcher: SearchEntriesAsync(searchFilter, OnlyMemberOf)
    Searcher->>Searcher: SelectAllMemberOfEntriesRecursively()
    loop each parent entry
        Searcher->>Searcher: SearchEntriesAsync(distinguishedNameFilter, requiredEntryAttributes)
        Searcher->>LDAP: SearchAsync
        LDAP-->>Searcher: parent entry
    end
    Searcher-->>Caller: LDAPSearchResult
Loading

File-Level Changes

Change Details Files
Convert the AD user DTO to an immutable record with constructor-based initialization and preserved account-control validation.
  • Replace mutable setters with init-only nullable properties.
  • Add an all-properties constructor while retaining existing constructor paths.
  • Move UAC flag parsing into a dedicated parser and implement secure cloning with record nondestructive mutation.
  • Require callers to provide the user distinguished name during account creation.
src/Bitai.LDAPHelper.DTO/LDAPMsADUserAccount.cs
src/Bitai.LDAPHelper/AccountManager.cs
tests/Bitai.LDAPHelper.Tests/AccountManagerAdapterTests.cs
Extend search functionality and adjust error reporting for clearer, reusable LDAP operations.
  • Add SearchParentEntriesAsync overload accepting already-loaded entries.
  • Refine parent-entry traversal and error handling.
  • Normalize LDAP search and authentication failure messages.
  • Add SearchLimits string representation.
src/Bitai.LDAPHelper/Searcher.cs
src/Bitai.LDAPHelper/Authenticator.cs
src/Bitai.LDAPHelper/SearchLimits.cs
Update the mock LDAP provider and test fixtures to model the Bitai AD namespace and revised attribute conventions.
  • Reseed domains, containers, users, groups, computers, relationships, mail addresses, and hostnames under bitai.com.
  • Use containerDN for mock object placement and Name instead of cn for computer/group/user lookup scenarios.
  • Seed mock data from the persistent connection factory and update Name-based filtering.
  • Update test entries and base search DN to match the new mock schema.
adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/LdapData/MockLdapDataSeeder.cs
adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/MockLdapPersistentConnectionAdapter.cs
adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/MockLdapPersistentConnectionFactoryAdapter.cs
adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/MockLdapAttributeAdapter.cs
tests/Bitai.LDAPHelper.Tests/BaseTests.cs
Apply formatting and minor project/mock adapter maintenance changes.
  • Reformat Novell connection factory and several helper classes.
  • Adjust mock factory documentation and constructor formatting.
  • Update project file changes associated with the implementation.
adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/MockLdapConnectionFactoryAdapter.cs
adapters/Bitai.LDAPHelper.LdapAdapters.Novell/NovellLdapConnectionFactoryAdapter.cs
src/Bitai.LDAPHelper/AccountManager.cs
src/Bitai.LDAPHelper/Searcher.cs
src/Bitai.LDAPHelper.DTO/Bitai.LDAPHelper.DTO.csproj
src/Bitai.LDAPHelper/Bitai.LDAPHelper.csproj
adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock.csproj
tests/Bitai.LDAPHelper.Tests/Bitai.LDAPHelper.Tests.csproj

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/MockLdapPersistentConnectionAdapter.cs" line_range="193-197" />
<code_context>
             return MatchWildcard(entry.DistinguishedName, value);
         }
-        else if (filter.Contains("(cn="))
+        else if (filter.Contains("(Name="))
         {
-            var value = ExtractFilterValue(filter, "cn");
-            var cn = entry.GetAttributeSet().GetAttribute("cn")?.StringValue;
+            var value = ExtractFilterValue(filter, "Name");
+            var cn = entry.GetAttributeSet().GetAttribute("Name")?.StringValue;
             return MatchWildcard(cn, value);
         }
         else if (filter.Contains("(objectSid="))
</code_context>
<issue_to_address>
**issue (bug_risk):** The mock now handles CN filters only when the filter contains `(Name=...)` and then looks up the case-sensitive `Name` key, but seeded users and groups still add `cn` and lowercase `name`; those entries therefore return no match for name searches in the persistent mock.

**Triggers:** When the persistent mock is used to search seeded users or groups by the normal LDAP `cn` attribute.

**Suggested fix:** Support `(cn=...)` and read the actual `cn` attribute, or normalize mock attribute names case-insensitively and consistently seed the same attribute.
</issue_to_address>

### Comment 2
<location path="src/Bitai.LDAPHelper.DTO/LDAPMsADUserAccount.cs" line_range="32-33" />
<code_context>
+        /// <param name="distinguishedNameOfContainer">Container distinguished name of user account.</param>
+        public LDAPMsADUserAccount(string distinguishedNameOfContainer) : this()
+        {
+            DistinguishedNameOfContainer = distinguishedNameOfContainer
+                ?? throw new ArgumentNullException(nameof(distinguishedNameOfContainer));
+        }
+
</code_context>
<issue_to_address>
**issue (bug_risk):** The single-argument constructor accepts an empty `distinguishedNameOfContainer`, whereas the previous constructor rejected both null and empty values; callers can now construct an invalid account that later fails during account creation.

**Triggers:** When a caller passes `string.Empty` as the container distinguished name.

**Suggested fix:** Use `string.IsNullOrEmpty(distinguishedNameOfContainer)` before throwing, preserving the previous contract.

```suggestion
            DistinguishedNameOfContainer = string.IsNullOrEmpty(distinguishedNameOfContainer)
                ? throw new ArgumentNullException(nameof(distinguishedNameOfContainer))
                : distinguishedNameOfContainer;
```
</issue_to_address>

### Comment 3
<location path="src/Bitai.LDAPHelper/AccountManager.cs" line_range="57-58" />
<code_context>
                 if (string.IsNullOrEmpty(newUserAccount.DistinguishedNameOfContainer))
                     throw new DataValidationException($"{nameof(newUserAccount.DistinguishedNameOfContainer)} is required.");

+                if (string.IsNullOrEmpty(newUserAccount.DistinguishedName))
+                    throw new DataValidationException($"{nameof(newUserAccount.DistinguishedName)} is required. Set the value: CN={newUserAccount.Cn},{newUserAccount.DistinguishedNameOfContainer}");
+
                 if (string.IsNullOrEmpty(newUserAccount.Cn))
</code_context>
<issue_to_address>
**issue (broader_impact):** Account creation now rejects any account whose full distinguished name is missing instead of deriving `CN={Cn},{DistinguishedNameOfContainer}` as the removed normalization method did; existing callers that provide only a container DN receive a validation failure and no account is created.

**Triggers:** When callers use the existing container-only construction pattern and omit `DistinguishedName`.

**Suggested fix:** Either retain the automatic DN initialization before validation or make the new full-DN requirement an explicit breaking API change and update all callers.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 3 findings to address first, and the DTO and account-creation changes alter LDAP account records, including requiring callers to supply the distinguished name and removing membership handling; a wrong value or placement could persist in the directory and require cleanup or recreation. Reverting restores the previous behavior, but it does not automatically repair accounts already created with incorrect attributes.

Blocking findings: adapters/Bitai.LDAPHelper.LdapAdapters.LdapHelperMock/MockLdapPersistentConnectionAdapter.cs:197, src/Bitai.LDAPHelper.DTO/LDAPMsADUserAccount.cs:33, src/Bitai.LDAPHelper/AccountManager.cs:58


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment on lines +193 to 197
else if (filter.Contains("(Name="))
{
var value = ExtractFilterValue(filter, "cn");
var cn = entry.GetAttributeSet().GetAttribute("cn")?.StringValue;
var value = ExtractFilterValue(filter, "Name");
var cn = entry.GetAttributeSet().GetAttribute("Name")?.StringValue;
return MatchWildcard(cn, value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): The mock now handles CN filters only when the filter contains (Name=...) and then looks up the case-sensitive Name key, but seeded users and groups still add cn and lowercase name; those entries therefore return no match for name searches in the persistent mock.

Triggers: When the persistent mock is used to search seeded users or groups by the normal LDAP cn attribute.

Suggested fix: Support (cn=...) and read the actual cn attribute, or normalize mock attribute names case-insensitively and consistently seed the same attribute.

Comment on lines +32 to +33
DistinguishedNameOfContainer = distinguishedNameOfContainer
?? throw new ArgumentNullException(nameof(distinguishedNameOfContainer));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): The single-argument constructor accepts an empty distinguishedNameOfContainer, whereas the previous constructor rejected both null and empty values; callers can now construct an invalid account that later fails during account creation.

Triggers: When a caller passes string.Empty as the container distinguished name.

Suggested fix: Use string.IsNullOrEmpty(distinguishedNameOfContainer) before throwing, preserving the previous contract.

Suggested change
DistinguishedNameOfContainer = distinguishedNameOfContainer
?? throw new ArgumentNullException(nameof(distinguishedNameOfContainer));
DistinguishedNameOfContainer = string.IsNullOrEmpty(distinguishedNameOfContainer)
? throw new ArgumentNullException(nameof(distinguishedNameOfContainer))
: distinguishedNameOfContainer;

Comment on lines +57 to +58
if (string.IsNullOrEmpty(newUserAccount.DistinguishedName))
throw new DataValidationException($"{nameof(newUserAccount.DistinguishedName)} is required. Set the value: CN={newUserAccount.Cn},{newUserAccount.DistinguishedNameOfContainer}");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (broader_impact): Account creation now rejects any account whose full distinguished name is missing instead of deriving CN={Cn},{DistinguishedNameOfContainer} as the removed normalization method did; existing callers that provide only a container DN receive a validation failure and no account is created.

Triggers: When callers use the existing container-only construction pattern and omit DistinguishedName.

Suggested fix: Either retain the automatic DN initialization before validation or make the new full-DN requirement an explicit breaking API change and update all callers.

@bitai-cs
bitai-cs merged commit 10ff3a4 into main Oct 1, 2026
3 checks passed
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