From edf694b8d4a13acfdc30b2f54a492ab3cc442b3e Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Tue, 27 Jan 2026 12:55:04 -0800 Subject: [PATCH] Use Scene result for SingleUserScene (#6909) * Scenes should return resulting data in the result object The result is for data that cannot be known by the client requesting the scene and the mangle map used for mangling input values to enable parallelizing tests * Fix filenames * SingleUserScene now has a return value of various created User data * 1/100 too frequent for false test failures --- .../EnumerationProtectionHelpersTests.cs | 4 +-- ...trollerTest.cs => QueryControllerTests.cs} | 0 ...ntrollerTest.cs => SeedControllerTests.cs} | 2 +- util/Seeder/Factories/UserSeeder.cs | 34 ++----------------- util/Seeder/IScene.cs | 2 +- util/Seeder/Scenes/SingleUserScene.cs | 34 +++++++++++++------ 6 files changed, 30 insertions(+), 46 deletions(-) rename test/SeederApi.IntegrationTest/{QueryControllerTest.cs => QueryControllerTests.cs} (100%) rename test/SeederApi.IntegrationTest/{SeedControllerTest.cs => SeedControllerTests.cs} (99%) diff --git a/test/Core.Test/Utilities/EnumerationProtectionHelpersTests.cs b/test/Core.Test/Utilities/EnumerationProtectionHelpersTests.cs index 68ac8af5d0..0f8ac56c22 100644 --- a/test/Core.Test/Utilities/EnumerationProtectionHelpersTests.cs +++ b/test/Core.Test/Utilities/EnumerationProtectionHelpersTests.cs @@ -98,7 +98,7 @@ public class EnumerationProtectionHelpersTests var hmacKey = RandomNumberGenerator.GetBytes(32); var salt1 = "user1@example.com"; var salt2 = "user2@example.com"; - var range = 100; + var range = 10_000; // Act var result1 = EnumerationProtectionHelpers.GetIndexForInputHash(hmacKey, salt1, range); @@ -117,7 +117,7 @@ public class EnumerationProtectionHelpersTests var hmacKey1 = RandomNumberGenerator.GetBytes(32); var hmacKey2 = RandomNumberGenerator.GetBytes(32); var salt = "test@example.com"; - var range = 100; + var range = 10_000; // Act var result1 = EnumerationProtectionHelpers.GetIndexForInputHash(hmacKey1, salt, range); diff --git a/test/SeederApi.IntegrationTest/QueryControllerTest.cs b/test/SeederApi.IntegrationTest/QueryControllerTests.cs similarity index 100% rename from test/SeederApi.IntegrationTest/QueryControllerTest.cs rename to test/SeederApi.IntegrationTest/QueryControllerTests.cs diff --git a/test/SeederApi.IntegrationTest/SeedControllerTest.cs b/test/SeederApi.IntegrationTest/SeedControllerTests.cs similarity index 99% rename from test/SeederApi.IntegrationTest/SeedControllerTest.cs rename to test/SeederApi.IntegrationTest/SeedControllerTests.cs index 1d081d019e..39139903d8 100644 --- a/test/SeederApi.IntegrationTest/SeedControllerTest.cs +++ b/test/SeederApi.IntegrationTest/SeedControllerTests.cs @@ -45,7 +45,7 @@ public class SeedControllerTests : IClassFixture, I Assert.NotNull(result); Assert.NotNull(result.MangleMap); - Assert.Null(result.Result); + Assert.NotNull(result.Result); } [Fact] diff --git a/util/Seeder/Factories/UserSeeder.cs b/util/Seeder/Factories/UserSeeder.cs index 4fc456981c..9b80dbef3c 100644 --- a/util/Seeder/Factories/UserSeeder.cs +++ b/util/Seeder/Factories/UserSeeder.cs @@ -1,5 +1,4 @@ -using System.Globalization; -using Bit.Core.Entities; +using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Utilities; using Bit.RustSDK; @@ -10,13 +9,6 @@ namespace Bit.Seeder.Factories; public struct UserData { public string Email; - public Guid Id; - public string? Key; - public string? PublicKey; - public string? PrivateKey; - public string? ApiKey; - public KdfType Kdf; - public int KdfIterations; } public class UserSeeder(RustSdkService sdkService, IPasswordHasher passwordHasher, MangleId mangleId) @@ -75,30 +67,8 @@ public class UserSeeder(RustSdkService sdkService, IPasswordHasher { - { expectedUserData.Email, MangleEmail(expectedUserData.Email) }, - { expectedUserData.Id.ToString(), user.Id.ToString() }, - { expectedUserData.Kdf.ToString(), user.Kdf.ToString() }, - { expectedUserData.KdfIterations.ToString(CultureInfo.InvariantCulture), user.KdfIterations.ToString(CultureInfo.InvariantCulture) } + { expectedUserData.Email, user.Email }, }; - if (expectedUserData.Key != null) - { - mangleMap[expectedUserData.Key] = user.Key; - } - - if (expectedUserData.PublicKey != null) - { - mangleMap[expectedUserData.PublicKey] = user.PublicKey; - } - - if (expectedUserData.PrivateKey != null) - { - mangleMap[expectedUserData.PrivateKey] = user.PrivateKey; - } - - if (expectedUserData.ApiKey != null) - { - mangleMap[expectedUserData.ApiKey] = user.ApiKey; - } return mangleMap; } diff --git a/util/Seeder/IScene.cs b/util/Seeder/IScene.cs index 6f513973ba..e6d38e3673 100644 --- a/util/Seeder/IScene.cs +++ b/util/Seeder/IScene.cs @@ -72,7 +72,7 @@ public interface IScene : IScene where TRequest : class /// and entity tracking information. The explicit interface implementations allow dynamic invocation /// while preserving type safety in the implementation. /// -public interface IScene : IScene where TRequest : class where TResult : class +public interface IScene : IScene where TRequest : class { /// /// Seeds data based on the provided strongly-typed request and returns typed result data. diff --git a/util/Seeder/Scenes/SingleUserScene.cs b/util/Seeder/Scenes/SingleUserScene.cs index df941c7f59..f7cec192fd 100644 --- a/util/Seeder/Scenes/SingleUserScene.cs +++ b/util/Seeder/Scenes/SingleUserScene.cs @@ -4,10 +4,22 @@ using Bit.Seeder.Factories; namespace Bit.Seeder.Scenes; +public struct SingleUserSceneResult +{ + public Guid UserId { get; init; } + public string Kdf { get; init; } + public int KdfIterations { get; init; } + public string Key { get; init; } + public string PublicKey { get; init; } + public string PrivateKey { get; init; } + public string ApiKey { get; init; } + +} + /// /// Creates a single user using the provided account details. /// -public class SingleUserScene(UserSeeder userSeeder, IUserRepository userRepository) : IScene +public class SingleUserScene(UserSeeder userSeeder, IUserRepository userRepository) : IScene { public class Request { @@ -17,22 +29,24 @@ public class SingleUserScene(UserSeeder userSeeder, IUserRepository userReposito public bool Premium { get; set; } = false; } - public async Task SeedAsync(Request request) + public async Task> SeedAsync(Request request) { var user = userSeeder.CreateUser(request.Email, request.EmailVerified, request.Premium); await userRepository.CreateAsync(user); - return new SceneResult(mangleMap: userSeeder.GetMangleMap(user, new UserData + return new SceneResult(result: new SingleUserSceneResult + { + UserId = user.Id, + Kdf = user.Kdf.ToString(), + KdfIterations = user.KdfIterations, + Key = user.Key!, + PublicKey = user.PublicKey!, + PrivateKey = user.PrivateKey!, + ApiKey = user.ApiKey!, + }, mangleMap: userSeeder.GetMangleMap(user, new UserData { Email = request.Email, - Id = user.Id, - Key = user.Key, - PublicKey = user.PublicKey, - PrivateKey = user.PrivateKey, - ApiKey = user.ApiKey, - Kdf = user.Kdf, - KdfIterations = user.KdfIterations, })); } }