Skip to content

Enhance seeder with additional cipher types and architectural refactorings#6935

Merged
theMickster merged 6 commits intomainfrom
unifiedTestData/all-cipher-types
Feb 4, 2026
Merged

Enhance seeder with additional cipher types and architectural refactorings#6935
theMickster merged 6 commits intomainfrom
unifiedTestData/all-cipher-types

Conversation

@theMickster
Copy link
Copy Markdown
Contributor

@theMickster theMickster commented Feb 2, 2026

💡 Before starting your review, remember that Rome wasn't built in a day nor will the Seeder be in a single pull request

🎟️ Tracking

📔 Objective

Implement required refactoring to decouple and standardize many of the components that make up the Seeder library.

  • Decomposed monolithic CipherSeeder.cs
    • Created type-specific factories
    • Extracted shared encryption logic
    • Created extensions for cipher-type data transformations
  • Added support for additional Cipher Types
  • Implemented a Distribution System for percentage based selection of mock org data to replace the ad-hoc distribution logic
  • Refactored data generators
    • Added GeneratorContext as lazy-loading container for all generators
    • Implemented specific generators as needed.
    • Ensured all only had a single purpose and meaning
    • Added region-aware data generation (Card, Identity, Username) supporting 6+ geographic regions
  • Significantly improved the UserSeeder by removing all responsibility for handling email manging
    • MangleId is about test orchestration, not user creation.
    • "Create a user with this email" → Factory concern
    • "Prefix emails so test runs don't collide" → Scene/orchestration concern
    • If a Scene needs test isolation, it should own that. If a Recipe doesn't need isolation (like OrganizationWithVaultRecipe using static methods), it shouldn't be forced to.

Code Quality
- Refactored all factories to consistent Create() naming pattern
- Unified seeder visibility to internal with proper InternalsVisibleTo for tests
- Split relationship entities into dedicated seeders (CollectionUserSeeder, GroupUserSeeder)
- Extracted organizational structure data to Data/Static/

Documentation
- Updated CLAUDE.md to focus on quick reference and pattern decisions
- Enhanced README.md with Helpers section and folder structure guide
- Created comprehensive Data/README.md with generator/distribution tables
- Added DbSeederUtility/CLAUDE.md for CLI-specific guidance

📝 I executed 7-10 local code reviews while working through this pull request using the out-of-the-box Claude Code Review command & our Bitwarden Claude Code command. I resolved various findings and architectural suggestions as I went.

return value;
}
}
return _buckets[^1].Value;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

📝 Return last bucket for out-of-range indices (graceful degradation). This handles rounding errors where cumulative counts don't exactly match total.

/// The workaround is a known test workaround that doesn't affect production code.
/// </summary>
[Fact]
public void SecureNote_SameSeed_ProducesSameOutput()
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

📝 Bogus 35.0+ has an edge case where Password() can infinite loop with certain seed/index combinations in WiFi/Database note categories. Limiting iterations is a test-only workaround that doesn't affect production usage where variety is high.

Comment thread util/Seeder/Helpers/StableHash.cs Outdated
Comment thread util/Seeder/Recipes/OrganizationWithVaultRecipe.cs
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

♻️ Upcoming work

TODO: Add password override parameter
Currently all seeded users share the same password for dev convenience.
Future: Support per-user or pattern-based passwords (e.g., "Pass-{username}") for more realistic testing scenarios.

@@ -32,16 +32,16 @@ public class CipherViewDto
public LoginViewDto? Login { get; set; }
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

♻️ Potential upcoming work

TODO: Add TOTP (2FA) support to LoginViewDto
Real logins often have Time-based One-Time Password seeds.
Need TotpSeed property (string, optional) that generators can populate with realistic authenticator seeds (e.g., "otpauth://totp/...")
This enables testing of TOTP generation/validation in vault scenarios.
No clue how to do this yet, but together we can figure it out.

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.

There are a good number of ways to use a seed to make TOTPs. This feels especially low-priority to need to test to me, as we're not testing the user's security itself. I suppose some use cases will "need" it but not totally sure what those are, in a hard-required sense.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure thing; I wasn't sure where it fit in the priority list. Thanks for the info 😃

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 2, 2026

Logo
Checkmarx One – Scan Summary & Details6bdc5cc6-97b9-4fe2-b832-192a2b3ca137

New Issues (1)

Checkmarx found the following issues in this Pull Request

# Severity Issue Source File / Package Checkmarx Insight
1 MEDIUM Use_Of_Hardcoded_Password /util/Seeder/Factories/UserSeeder.cs: 12
detailsThe application uses the hard-coded password DefaultPassword for authentication purposes, either using it to verify users' identities, or to acces...
Attack Vector
Fixed Issues (2)

Great job! The following issues were fixed in this Pull Request

Severity Issue Source File / Package
MEDIUM Use_Of_Hardcoded_Password /util/Seeder/Factories/UserSeeder.cs: 50
MEDIUM Use_Of_Hardcoded_Password /util/Seeder/Factories/UserSeeder.cs: 62

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Before this class, recipes had 7+ fields for generators and a long InitializeGenerators() method. Now recipes have 1 field (_ctx) andgenerators are accessed via properties.

Design goal: Make adding generators a 3-line change (field, property, done) without touching recipe constructor or initialization logic.


namespace Bit.Seeder.Data.Generators;

/// <summary>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

📝 SSH keys use a pre-generated pool because RSA.Create() uses system RNG (not our seed). Keys are marked with -----BEGIN FAKE RSA PRIVATE KEY----- headers to prevent accidental production use. Cross-run reproducibility is not guaranteed for SSH key content.

We really just want nice looking fake data; we don't want some testing tool using them.
That is so far out of scope right now; it's not even on the horizon

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.

Does the "fake" addition really stop anyone from using it though? And what do scanners say? I would want it to pass and validators our user experience might have first.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, I don't think it would stop anyone from using them. I will look closer into our static code analyzers to see if anything barks. In terms of the UI, it 'seems' to pass validation on the frontend (as in I don't see any toaster messages) when I open the modal.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

♻️Upcoming work
No organizational policies are currently configured. We'll add policy seeding (2FA requirements, Master Password policies, etc.).

@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.23%. Comparing base (51aa419) to head (939635b).
⚠️ Report is 16 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6935      +/-   ##
==========================================
- Coverage   60.01%   56.23%   -3.79%     
==========================================
  Files        1971     1976       +5     
  Lines       87090    87523     +433     
  Branches     7759     7809      +50     
==========================================
- Hits        52266    49216    -3050     
- Misses      32928    36478    +3550     
+ Partials     1896     1829      -67     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@theMickster theMickster added the ai-review Request a Claude code review label Feb 2, 2026
@theMickster theMickster marked this pull request as ready for review February 2, 2026 15:02
@theMickster theMickster requested a review from a team February 2, 2026 15:03
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Feb 2, 2026

Claude finished @theMickster's task in 3m 42s —— View job


Code Review Complete

I've conducted a thorough review of this PR which enhances the Seeder library with additional cipher types and architectural refactorings. Overall, this is a well-structured PR with good separation of concerns and comprehensive test coverage. Below are my findings organized by priority.


✅ What's Good

  1. Clean Architecture: The decomposition of the monolithic CipherSeeder.cs into type-specific factories (LoginCipherSeeder, CardCipherSeeder, IdentityCipherSeeder, SecureNoteCipherSeeder, SshKeyCipherSeeder) follows single responsibility principle well.

  2. Distribution System: The Distribution<T> class (util/Seeder/Data/Distributions/Distribution.cs) is a clean abstraction for percentage-based selection with good validation and deterministic behavior.

  3. Lazy Initialization: GeneratorContext effectively uses lazy initialization to avoid creating unused generator instances.

  4. Test Coverage: Good integration tests in DistributionTests.cs and GeneratorContextTests.cs covering edge cases, determinism, and round-trip encryption.

  5. ManglerService Design: The IManglerService / ManglerService / NoOpManglerService pattern cleanly separates test isolation concerns from the seeder logic itself, addressing the discussion points in the PR comments.

  6. SSH Key Security: The SshKeyDataGenerator correctly marks fake keys with -----BEGIN FAKE RSA PRIVATE KEY----- headers to prevent accidental production use (util/Seeder/Data/Generators/SshKeyDataGenerator.cs:71).


🟡 Suggestions (Non-Blocking)

1. FolderNameGenerator Pool Size Issue

File: util/Seeder/Data/Generators/FolderNameGenerator.cs:17-20

The .Distinct() call may result in fewer than _namePoolSize (50) unique names if Commerce.Department() returns duplicates. This could reduce folder name variety.

_folderNames = Enumerable.Range(0, _namePoolSize)
    .Select(_ => faker.Commerce.Department())
    .Distinct()
    .ToArray();

Consider generating more names initially (e.g., 100) to ensure the target unique count after deduplication, or document the expected minimum.

2. Distribution.GetCounts Simplification

File: util/Seeder/Data/Distributions/Distribution.cs:54-64

Per @MGibson1's review comment, the last bucket handling could be simplified. The current implementation is correct but slightly more complex than necessary.

3. Double Mangling in OrganizationWithVaultRecipe

File: util/Seeder/Recipes/OrganizationWithVaultRecipe.cs:78-80

The email is mangled explicitly, then passed to UserSeeder.Create which may mangle again. The UserSeeder.Create method skips mangling when keys are provided, but this pattern could be clearer:

var email = $"user{i}@{options.Domain}";
var mangledEmail = manglerService.Mangle(email);
var userKeys = RustSdkService.GenerateUserKeys(mangledEmail, UserSeeder.DefaultPassword);
var memberUser = UserSeeder.Create(mangledEmail, passwordHasher, manglerService, keys: userKeys);

Since userKeys is provided, UserSeeder.Create will skip mangling. This is correct but relies on implementation details. Consider documenting this behavior more explicitly or passing a flag to indicate pre-mangled emails.


🔴 Issues to Address

1. Hardcoded Password - Checkmarx Finding

File: util/Seeder/Factories/UserSeeder.cs:12

internal const string DefaultPassword = "asdfasdfasdf";

This is flagged by Checkmarx as Use_Of_Hardcoded_Password. While this is intentional for seeding test data (and documented in the recipe comment at line 31), consider:

  1. Adding a code comment explaining this is intentional for test seeding only
  2. Moving it to a configuration value that can be overridden
  3. Adding a SuppressMessage attribute with justification if you want to suppress the warning explicitly

The current approach is acceptable for a seeder utility, but the warning should be acknowledged or suppressed with documentation.

2. Potential Thread Safety Issue in SshKeyDataGenerator

File: util/Seeder/Data/Generators/SshKeyDataGenerator.cs:37-38

The lazy initialization is thread-safe, but if multiple threads access _keyPool.Value simultaneously during first access, all will wait for pool generation. For a 500-key RSA pool, this could be slow. Consider:

  • Reducing pool size for faster startup
  • Using Lazy<T>(LazyThreadSafetyMode.ExecutionAndPublication) explicitly (current default is fine)
  • Documenting the startup cost

This is minor since it only affects first access.


📝 Architectural Notes

The discussion between reviewers about mangling responsibilities has been well-resolved:

  • ManglerService handles the "how" of mangling
  • Scenes/Recipes decide "when" to mangle via DI configuration (TestPlayIdTrackingEnabled)
  • Factories remain stateless and receive the service

The MangleId class being private to ManglerService (per @MGibson1's suggestion in the comments) was addressed - the current implementation at util/Seeder/Services/ManglerService.cs:37-42 has it as a private class, which is correct.


Summary

This is a solid PR that significantly improves the Seeder library's architecture. The main actionable item is addressing the Checkmarx warning for the hardcoded password - even if just with documentation/suppression. The other suggestions are non-blocking improvements.

Recommended: Address the hardcoded password warning, then this PR is ready to merge.

@MGibson1 MGibson1 self-requested a review February 2, 2026 16:48
Copy link
Copy Markdown
Member

@MGibson1 MGibson1 left a comment

Choose a reason for hiding this comment

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

I think the discrepency on mangling is really the only thing I'd like to get aligned with.

As I mention in one of the comments these seeders have two use-cases

  1. to create development environments that are human-usable
  2. to create single-use, parallelizable test data where magic strings exist only to make tests more readable and the actual value doesn't matter

I'd like our seeders to handle both cases because they are the location of all the expertise in creating the object, moving that out of seeders just makes things more distributed and muddied.

I like the proposed solution of a ManglerService that a given seeder can always call, but only mangles based on execution context. I believe it is true that we will either want everything mangled or nothing mangled.

Comment on lines +12 to +25
/// <summary>
/// Creates a distribution from percentage buckets.
/// </summary>
/// <param name="buckets">Value-percentage pairs that must sum to 1.0 (within 0.001 tolerance).</param>
/// <exception cref="ArgumentException">Thrown when percentages don't sum to 1.0.</exception>
public Distribution(params (T Value, double Percentage)[] buckets)
{
var total = buckets.Sum(b => b.Percentage);
if (Math.Abs(total - 1.0) > 0.001)
{
throw new ArgumentException($"Percentages must sum to 1.0, got {total}");
}
_buckets = buckets;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

todo: just normalize the buckets when you get them to remove the restriction

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Will you please explain and clarify what you mean here? I'm not tracking ya

Comment on lines +48 to +64
/// <summary>
/// Returns all values with their calculated counts for a given total.
/// The last bucket receives any remainder from rounding.
/// </summary>
/// <param name="total">Total number of items to distribute.</param>
/// <returns>Sequence of value-count pairs.</returns>
public IEnumerable<(T Value, int Count)> GetCounts(int total)
{
var remaining = total;
for (var i = 0; i < _buckets.Length - 1; i++)
{
var count = (int)(total * _buckets[i].Percentage);
yield return (_buckets[i].Value, count);
remaining -= count;
}
yield return (_buckets[^1].Value, remaining);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: I don't think the last bucket is a special case

Suggested change
/// <summary>
/// Returns all values with their calculated counts for a given total.
/// The last bucket receives any remainder from rounding.
/// </summary>
/// <param name="total">Total number of items to distribute.</param>
/// <returns>Sequence of value-count pairs.</returns>
public IEnumerable<(T Value, int Count)> GetCounts(int total)
{
var remaining = total;
for (var i = 0; i < _buckets.Length - 1; i++)
{
var count = (int)(total * _buckets[i].Percentage);
yield return (_buckets[i].Value, count);
remaining -= count;
}
yield return (_buckets[^1].Value, remaining);
}
/// <summary>
/// Returns all values with their calculated counts for a given total.
/// The last bucket receives any remainder from rounding.
/// </summary>
/// <param name="total">Total number of items to distribute.</param>
/// <returns>Sequence of value-count pairs.</returns>
public IEnumerable<(T Value, int Count)> GetCounts(int total)
{
for (var i = 0; i < _buckets.Length; i++)
{
var count = (int)(total * _buckets[i].Percentage);
yield return (_buckets[i].Value, count);
}
}

Copy link
Copy Markdown
Contributor Author

@theMickster theMickster Feb 2, 2026

Choose a reason for hiding this comment

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

Does it still work as it does now with the same distributions?
If so then I'm fine with the change 😃

Comment on lines +11 to +12
/// Realistic distribution based on breach data and security research.
/// 25% VeryWeak, 30% Weak, 25% Fair, 15% Strong, 5% VeryStrong
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

where's this data come from?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Claude.
I didn't waste time researching nor really mind what the total are in the end as I just wanted something that smelled reasonable to make realistic vault data.
Eventually, we'll have these will be inputs to the recipe.

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.

A ⛏️ like my other comment -- and this can just be a future PR to tweak -- but I think / hope this is skewed more toward fair. This makes me want to suggest something more aligned with your "developer" option above and to have additional distributions for "power users" or similar.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree that with these distributions we can have all sorts of different distributions for all different types of user vaults and organization vaults. And yes, this is not something to spend too much thought time on at this point.

We can have the 'boomer' distribution that leans towards the less secure side and then the 'bitwarden' distribution that's on the way secure side. And these distributions can all be easily added and maintained all outside the main recipes & steps. 😃

Comment thread util/Seeder/Helpers/EmailMangler.cs Outdated
Comment thread util/Seeder/Scenes/SingleUserScene.cs Outdated
Comment thread util/Seeder/Helpers/EmailMangler.cs Outdated
/// </remarks>
public class EmailMangler
{
private readonly MangleId _mangleId = new();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This should probably just be the play id, do we want to ever mangle things that aren't associated with a play?

@theMickster
Copy link
Copy Markdown
Contributor Author

I think the discrepency on mangling is really the only thing I'd like to get aligned with.
....

Works for me. I'm for a chat.
I see the Seeders and Factories differently and needing to know zero state whatsoever. I also see them as internal to the library and should not be injected into a scene (hence my refactoring). If mangling is required, then I see the tracking of the mangling as a responsibility of the Scene or Recipe.

Also, what other data points other than the email address must be mangled?

Copy link
Copy Markdown
Contributor

@withinfocus withinfocus left a comment

Choose a reason for hiding this comment

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

A few low-priority comments.

I tend to agree with Mick's approach that we'd have specific manglers and use those sometimes or not at all; ome use cases will have mangling and some data just doesn't need it or would be harmless.

Despite some inefficiencies are the "ingredients" necessary for further breakdown? What are the scenarios we envision implementing that require a different composition?

Comment thread util/DbSeederUtility/CLAUDE.md Outdated
Comment thread util/DbSeederUtility/CLAUDE.md Outdated
{
/// <summary>
/// Realistic enterprise mix based on typical usage patterns.
/// 60% Login, 15% SecureNote, 12% Card, 10% Identity, 3% SshKey
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.

ℹ️ Seems ... inaccurate to me. Something to ask about internally.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fair point and likely correct.
Without any access to environments outside my own, I took a random guess to get some data that 'looked' normal with plenty of examples of things other than logins.

Comment on lines +11 to +12
/// Realistic distribution based on breach data and security research.
/// 25% VeryWeak, 30% Weak, 25% Fair, 15% Strong, 5% VeryStrong
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.

A ⛏️ like my other comment -- and this can just be a future PR to tweak -- but I think / hope this is skewed more toward fair. This makes me want to suggest something more aligned with your "developer" option above and to have additional distributions for "power users" or similar.


namespace Bit.Seeder.Data.Generators;

/// <summary>
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.

Does the "fake" addition really stop anyone from using it though? And what do scanners say? I would want it to pass and validators our user experience might have first.

@@ -32,16 +32,16 @@ public class CipherViewDto
public LoginViewDto? Login { get; set; }
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.

There are a good number of ways to use a seed to make TOTPs. This feels especially low-priority to need to test to me, as we're not testing the user's security itself. I suppose some use cases will "need" it but not totally sure what those are, in a hard-required sense.

Comment thread util/Seeder/Recipes/OrganizationWithVaultRecipe.cs
Comment thread util/Seeder/CLAUDE.md Outdated
@theMickster theMickster requested a review from MGibson1 February 3, 2026 14:52
@theMickster theMickster requested a review from a team as a code owner February 4, 2026 14:52
@theMickster theMickster requested a review from JimmyVo16 February 4, 2026 14:52
internal FolderNameGenerator(int seed)
{
var faker = new Faker { Random = new Randomizer(seed) };

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.

🎨 SUGGESTED: The .Distinct() call on line 19 could result in fewer unique names if Commerce.Department() returns duplicates. This means _folderNames.Length may be less than _namePoolSize (50), potentially causing less diverse folder names than expected.

Consider either:

  1. Generating more names initially (e.g., 100) to ensure 50+ unique values after deduplication
  2. Documenting the expected minimum unique count

This is a minor edge case - the current behavior is functional, just may produce less variety than the constant suggests.

Copy link
Copy Markdown
Member

@MGibson1 MGibson1 left a comment

Choose a reason for hiding this comment

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

Commenting for your response to MangleId class access modifier.

Comment on lines +22 to +25
// When keys are provided, caller owns email/key consistency - don't mangle
var mangledEmail = keys == null ? manglerService.Mangle(email) : email;

keys ??= RustSdkService.GenerateUserKeys(mangledEmail, DefaultPassword);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking question: Under what circumstances are you expecting user keys to be provided?

Who is meant to produce those keys and how to they mangle to ensure tests can be executed in parallel?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We needed the symmetric key in the Recipe to make folders (at least I'm fairly certain we do).
And, it just felt a little odd for the Seeder to return a UserWithKeys or some tuple.

Comment thread util/SeederApi/Extensions/ServiceCollectionExtensions.cs
Comment thread util/Seeder/MangleId.cs Outdated
MGibson1
MGibson1 previously approved these changes Feb 4, 2026
withinfocus
withinfocus previously approved these changes Feb 4, 2026
Copy link
Copy Markdown
Contributor

@withinfocus withinfocus left a comment

Choose a reason for hiding this comment

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

Works for me, as for Gibson it seems.

JimmyVo16
JimmyVo16 previously approved these changes Feb 4, 2026
@theMickster theMickster merged commit 4eb9c4c into main Feb 4, 2026
54 of 55 checks passed
@theMickster theMickster deleted the unifiedTestData/all-cipher-types branch February 4, 2026 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request a Claude code review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants