From 507c3a105c2606e619877122522ba50ad0366356 Mon Sep 17 00:00:00 2001 From: Mick Letofsky Date: Thu, 19 Feb 2026 18:40:48 +0100 Subject: [PATCH] Refactoring structure of the CLI to be more maintainable long-term (#7042) * Refactoring structure of the CLI to be more maintainable long-term * Remove obvious comments & put back XML comments --- bitwarden-server.sln | 2 +- dev/setup_secrets.ps1 | 2 +- util/DbSeederUtility/Program.cs | 189 ------------------ util/Seeder/CLAUDE.md | 2 +- util/Seeder/README.md | 2 +- .../Commands/OrganizationCommand.cs | 40 ++++ .../Commands}/SeedArgs.cs | 7 +- util/SeederUtility/Commands/SeedCommand.cs | 115 +++++++++++ .../Commands}/VaultOrganizationArgs.cs | 2 +- .../Commands/VaultOrganizationCommand.cs | 49 +++++ .../Configuration}/GlobalSettingsFactory.cs | 4 +- .../ServiceCollectionExtension.cs | 8 +- util/SeederUtility/Program.cs | 22 ++ .../README.md | 34 ++-- .../SeederUtility.csproj} | 4 +- 15 files changed, 257 insertions(+), 225 deletions(-) delete mode 100644 util/DbSeederUtility/Program.cs create mode 100644 util/SeederUtility/Commands/OrganizationCommand.cs rename util/{DbSeederUtility => SeederUtility/Commands}/SeedArgs.cs (79%) create mode 100644 util/SeederUtility/Commands/SeedCommand.cs rename util/{DbSeederUtility => SeederUtility/Commands}/VaultOrganizationArgs.cs (99%) create mode 100644 util/SeederUtility/Commands/VaultOrganizationCommand.cs rename util/{DbSeederUtility => SeederUtility/Configuration}/GlobalSettingsFactory.cs (90%) rename util/{DbSeederUtility => SeederUtility/Configuration}/ServiceCollectionExtension.cs (83%) create mode 100644 util/SeederUtility/Program.cs rename util/{DbSeederUtility => SeederUtility}/README.md (81%) rename util/{DbSeederUtility/DbSeederUtility.csproj => SeederUtility/SeederUtility.csproj} (85%) diff --git a/bitwarden-server.sln b/bitwarden-server.sln index 409906e2d0..4f3b3c8bdf 100644 --- a/bitwarden-server.sln +++ b/bitwarden-server.sln @@ -131,7 +131,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.IntegrationTest", "tes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Seeder", "util\Seeder\Seeder.csproj", "{9A612EBA-1C0E-42B8-982B-62F0EE81000A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DbSeederUtility", "util\DbSeederUtility\DbSeederUtility.csproj", "{17A89266-260A-4A03-81AE-C0468C6EE06E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeederUtility", "util\SeederUtility\SeederUtility.csproj", "{17A89266-260A-4A03-81AE-C0468C6EE06E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RustSdk", "util\RustSdk\RustSdk.csproj", "{D1513D90-E4F5-44A9-9121-5E46E3E4A3F7}" EndProject diff --git a/dev/setup_secrets.ps1 b/dev/setup_secrets.ps1 index a41890bc46..88327e9c0a 100755 --- a/dev/setup_secrets.ps1 +++ b/dev/setup_secrets.ps1 @@ -28,7 +28,7 @@ $projects = @{ Scim = "../bitwarden_license/src/Scim" IntegrationTests = "../test/Infrastructure.IntegrationTest" SeederApi = "../util/SeederApi" - SeederUtility = "../util/DbSeederUtility" + SeederUtility = "../util/SeederUtility" } foreach ($key in $projects.keys) { diff --git a/util/DbSeederUtility/Program.cs b/util/DbSeederUtility/Program.cs deleted file mode 100644 index d72182bd67..0000000000 --- a/util/DbSeederUtility/Program.cs +++ /dev/null @@ -1,189 +0,0 @@ -using System.Diagnostics; -using AutoMapper; -using Bit.Core.Entities; -using Bit.Infrastructure.EntityFramework.Repositories; -using Bit.Seeder.Recipes; -using Bit.Seeder.Services; -using CommandDotNet; -using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.DependencyInjection; - -namespace Bit.DbSeederUtility; - -public class Program -{ - private static int Main(string[] args) - { - return new AppRunner() - .Run(args); - } - - [Command("organization", Description = "Seed an organization and organization users")] - public void Organization( - [Option('n', "Name", Description = "Name of organization")] - string name, - [Option('u', "users", Description = "Number of users to generate")] - int users, - [Option('d', "domain", Description = "Email domain for users")] - string domain - ) - { - // Create service provider with necessary services - var services = new ServiceCollection(); - ServiceCollectionExtension.ConfigureServices(services); - var serviceProvider = services.BuildServiceProvider(); - - // Get a scoped DB context - using var scope = serviceProvider.CreateScope(); - var scopedServices = scope.ServiceProvider; - var db = scopedServices.GetRequiredService(); - - var mapper = scopedServices.GetRequiredService(); - var passwordHasher = scopedServices.GetRequiredService>(); - var manglerService = scopedServices.GetRequiredService(); - var recipe = new OrganizationWithUsersRecipe(db, mapper, passwordHasher, manglerService); - recipe.Seed(name: name, domain: domain, users: users); - } - - [Command("vault-organization", Description = "Seed an organization with users and encrypted vault data (ciphers, collections, groups)")] - public void VaultOrganization(VaultOrganizationArgs args) - { - args.Validate(); - - var services = new ServiceCollection(); - ServiceCollectionExtension.ConfigureServices(services, enableMangling: args.Mangle); - var serviceProvider = services.BuildServiceProvider(); - - using var scope = serviceProvider.CreateScope(); - var scopedServices = scope.ServiceProvider; - - var manglerService = scopedServices.GetRequiredService(); - var recipe = new OrganizationWithVaultRecipe( - scopedServices.GetRequiredService(), - scopedServices.GetRequiredService(), - scopedServices.GetRequiredService>(), - manglerService); - - recipe.Seed(args.ToOptions()); - - if (!manglerService.IsEnabled) - { - return; - } - - var map = manglerService.GetMangleMap(); - Console.WriteLine("--- Mangled Data Map ---"); - foreach (var (original, mangled) in map) - { - Console.WriteLine($"{original} -> {mangled}"); - } - } - - [Command("seed", Description = "Seed database using fixture-based presets")] - public void Seed(SeedArgs args) - { - try - { - args.Validate(); - - // Handle list mode - no database needed - if (args.List) - { - var available = OrganizationFromPresetRecipe.ListAvailable(); - PrintAvailableSeeds(available); - return; - } - - // Create service provider - same pattern as other commands - var services = new ServiceCollection(); - ServiceCollectionExtension.ConfigureServices(services, enableMangling: args.Mangle); - var serviceProvider = services.BuildServiceProvider(); - - using var scope = serviceProvider.CreateScope(); - var scopedServices = scope.ServiceProvider; - - var db = scopedServices.GetRequiredService(); - var mapper = scopedServices.GetRequiredService(); - var passwordHasher = scopedServices.GetRequiredService>(); - var manglerService = scopedServices.GetRequiredService(); - - // Create recipe - CLI is "dumb", recipe handles complexity - var recipe = new OrganizationFromPresetRecipe(db, mapper, passwordHasher, manglerService); - - var stopwatch = Stopwatch.StartNew(); - - Console.WriteLine($"Seeding organization from preset '{args.Preset}'..."); - var result = recipe.Seed(args.Preset!, args.Password); - - stopwatch.Stop(); - PrintSeedResult(result, stopwatch.Elapsed); - } - catch (Exception ex) when (ex is ArgumentException or InvalidOperationException) - { - Console.Error.WriteLine($"Error: {ex.Message}"); - Environment.Exit(1); - } - } - - private static void PrintAvailableSeeds(AvailableSeeds available) - { - Console.WriteLine("Available Presets:"); - foreach (var preset in available.Presets) - { - Console.WriteLine($" - {preset}"); - } - Console.WriteLine(); - - Console.WriteLine("Available Fixtures:"); - foreach (var (category, fixtures) in available.Fixtures.OrderBy(kvp => kvp.Key)) - { - // Guard: Skip empty or single-character categories to prevent IndexOutOfRangeException - if (string.IsNullOrEmpty(category) || category.Length < 2) - { - continue; - } - - var categoryName = char.ToUpperInvariant(category[0]) + category[1..]; - Console.WriteLine($" {categoryName}:"); - foreach (var fixture in fixtures) - { - Console.WriteLine($" - {fixture}"); - } - } - - Console.WriteLine(); - Console.WriteLine("Use: DbSeeder.exe seed --preset "); - } - - private static void PrintSeedResult(SeedResult result, TimeSpan elapsed) - { - Console.WriteLine($"✓ Created organization (ID: {result.OrganizationId})"); - - if (result.OwnerEmail is not null) - { - Console.WriteLine($"✓ Owner: {result.OwnerEmail}"); - } - - if (result.UsersCount > 0) - { - Console.WriteLine($"✓ Created {result.UsersCount} users"); - } - - if (result.GroupsCount > 0) - { - Console.WriteLine($"✓ Created {result.GroupsCount} groups"); - } - - if (result.CollectionsCount > 0) - { - Console.WriteLine($"✓ Created {result.CollectionsCount} collections"); - } - - if (result.CiphersCount > 0) - { - Console.WriteLine($"✓ Created {result.CiphersCount} ciphers"); - } - - Console.WriteLine($"Done in {elapsed.TotalSeconds:F1}s"); - } -} diff --git a/util/Seeder/CLAUDE.md b/util/Seeder/CLAUDE.md index 9713c4c35b..6f1d06e59b 100644 --- a/util/Seeder/CLAUDE.md +++ b/util/Seeder/CLAUDE.md @@ -4,7 +4,7 @@ **For detailed pattern descriptions (Factories, Recipes, Models, Scenes, Queries, Data), read `README.md`.** -**For detailed usages of the Seeder library, read `util/DbSeederUtility/README.md` and `util/SeederApi/README.md`** +**For detailed usages of the Seeder library, read `util/SeederUtility/README.md` and `util/SeederApi/README.md`** ## Commands diff --git a/util/Seeder/README.md b/util/Seeder/README.md index f3e3fa45da..e19c1384e1 100644 --- a/util/Seeder/README.md +++ b/util/Seeder/README.md @@ -200,7 +200,7 @@ The Seeder is organized around six core patterns, each with a specific responsib **Configuration:** - SeederApi: Enabled when `GlobalSettings.TestPlayIdTrackingEnabled` is true -- DbSeederUtility: Enabled with `--mangle` CLI flag +- SeederUtility: Enabled with `--mangle` CLI flag --- diff --git a/util/SeederUtility/Commands/OrganizationCommand.cs b/util/SeederUtility/Commands/OrganizationCommand.cs new file mode 100644 index 0000000000..1304bd3126 --- /dev/null +++ b/util/SeederUtility/Commands/OrganizationCommand.cs @@ -0,0 +1,40 @@ +using AutoMapper; +using Bit.Core.Entities; +using Bit.Infrastructure.EntityFramework.Repositories; +using Bit.Seeder.Recipes; +using Bit.Seeder.Services; +using Bit.SeederUtility.Configuration; +using CommandDotNet; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; + +namespace Bit.SeederUtility.Commands; + +[Command("organization", Description = "Seed an organization and organization users")] +public class OrganizationCommand +{ + [DefaultCommand] + public void Execute( + [Option('n', "Name", Description = "Name of organization")] + string name, + [Option('u', "users", Description = "Number of users to generate")] + int users, + [Option('d', "domain", Description = "Email domain for users")] + string domain + ) + { + var services = new ServiceCollection(); + ServiceCollectionExtension.ConfigureServices(services); + var serviceProvider = services.BuildServiceProvider(); + + using var scope = serviceProvider.CreateScope(); + var scopedServices = scope.ServiceProvider; + var db = scopedServices.GetRequiredService(); + + var mapper = scopedServices.GetRequiredService(); + var passwordHasher = scopedServices.GetRequiredService>(); + var manglerService = scopedServices.GetRequiredService(); + var recipe = new OrganizationWithUsersRecipe(db, mapper, passwordHasher, manglerService); + recipe.Seed(name: name, domain: domain, users: users); + } +} diff --git a/util/DbSeederUtility/SeedArgs.cs b/util/SeederUtility/Commands/SeedArgs.cs similarity index 79% rename from util/DbSeederUtility/SeedArgs.cs rename to util/SeederUtility/Commands/SeedArgs.cs index 183e9be4dc..6bc2ebcd5b 100644 --- a/util/DbSeederUtility/SeedArgs.cs +++ b/util/SeederUtility/Commands/SeedArgs.cs @@ -1,6 +1,6 @@ using CommandDotNet; -namespace Bit.DbSeederUtility; +namespace Bit.SeederUtility.Commands; /// /// CLI argument model for the seed command. @@ -22,17 +22,14 @@ public class SeedArgs : IArgumentModel public void Validate() { - // List mode is standalone if (List) { return; } - // Must specify preset if (string.IsNullOrEmpty(Preset)) { - throw new ArgumentException( - "--preset must be specified. Use --list to see available presets."); + throw new ArgumentException("--preset must be specified. Use --list to see available presets."); } } } diff --git a/util/SeederUtility/Commands/SeedCommand.cs b/util/SeederUtility/Commands/SeedCommand.cs new file mode 100644 index 0000000000..f1779bd118 --- /dev/null +++ b/util/SeederUtility/Commands/SeedCommand.cs @@ -0,0 +1,115 @@ +using AutoMapper; +using Bit.Core.Entities; +using Bit.Infrastructure.EntityFramework.Repositories; +using Bit.Seeder.Recipes; +using Bit.Seeder.Services; +using Bit.SeederUtility.Configuration; +using CommandDotNet; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; + +namespace Bit.SeederUtility.Commands; + +[Command("seed", Description = "Seed database using fixture-based presets")] +public class SeedCommand +{ + [DefaultCommand] + public void Execute(SeedArgs args) + { + try + { + args.Validate(); + + if (args.List) + { + var available = OrganizationFromPresetRecipe.ListAvailable(); + PrintAvailableSeeds(available); + return; + } + + var services = new ServiceCollection(); + ServiceCollectionExtension.ConfigureServices(services, enableMangling: args.Mangle); + var serviceProvider = services.BuildServiceProvider(); + + using var scope = serviceProvider.CreateScope(); + var scopedServices = scope.ServiceProvider; + + var db = scopedServices.GetRequiredService(); + var mapper = scopedServices.GetRequiredService(); + var passwordHasher = scopedServices.GetRequiredService>(); + var manglerService = scopedServices.GetRequiredService(); + + var recipe = new OrganizationFromPresetRecipe(db, mapper, passwordHasher, manglerService); + + Console.WriteLine($"Seeding organization from preset '{args.Preset}'..."); + var result = recipe.Seed(args.Preset!, args.Password); + + PrintSeedResult(result); + } + catch (Exception ex) when (ex is ArgumentException or InvalidOperationException) + { + Console.Error.WriteLine($"Error: {ex.Message}"); + Environment.Exit(1); + } + } + + private static void PrintAvailableSeeds(AvailableSeeds available) + { + Console.WriteLine("Available Presets:"); + foreach (var preset in available.Presets) + { + Console.WriteLine($" - {preset}"); + } + Console.WriteLine(); + + Console.WriteLine("Available Fixtures:"); + foreach (var (category, fixtures) in available.Fixtures.OrderBy(kvp => kvp.Key)) + { + // Guard: Skip empty or single-character categories to prevent IndexOutOfRangeException + if (string.IsNullOrEmpty(category) || category.Length < 2) + { + continue; + } + + var categoryName = char.ToUpperInvariant(category[0]) + category[1..]; + Console.WriteLine($" {categoryName}:"); + foreach (var fixture in fixtures) + { + Console.WriteLine($" - {fixture}"); + } + } + + Console.WriteLine(); + Console.WriteLine("Use: SeederUtility seed --preset "); + } + + private static void PrintSeedResult(SeedResult result) + { + Console.WriteLine($"✓ Created organization (ID: {result.OrganizationId})"); + + if (result.OwnerEmail is not null) + { + Console.WriteLine($"✓ Owner: {result.OwnerEmail}"); + } + + if (result.UsersCount > 0) + { + Console.WriteLine($"✓ Created {result.UsersCount} users"); + } + + if (result.GroupsCount > 0) + { + Console.WriteLine($"✓ Created {result.GroupsCount} groups"); + } + + if (result.CollectionsCount > 0) + { + Console.WriteLine($"✓ Created {result.CollectionsCount} collections"); + } + + if (result.CiphersCount > 0) + { + Console.WriteLine($"✓ Created {result.CiphersCount} ciphers"); + } + } +} diff --git a/util/DbSeederUtility/VaultOrganizationArgs.cs b/util/SeederUtility/Commands/VaultOrganizationArgs.cs similarity index 99% rename from util/DbSeederUtility/VaultOrganizationArgs.cs rename to util/SeederUtility/Commands/VaultOrganizationArgs.cs index c54bddea37..3675f662cd 100644 --- a/util/DbSeederUtility/VaultOrganizationArgs.cs +++ b/util/SeederUtility/Commands/VaultOrganizationArgs.cs @@ -3,7 +3,7 @@ using Bit.Seeder.Factories; using Bit.Seeder.Options; using CommandDotNet; -namespace Bit.DbSeederUtility; +namespace Bit.SeederUtility.Commands; /// /// CLI argument model for the vault-organization command. diff --git a/util/SeederUtility/Commands/VaultOrganizationCommand.cs b/util/SeederUtility/Commands/VaultOrganizationCommand.cs new file mode 100644 index 0000000000..41851daa8e --- /dev/null +++ b/util/SeederUtility/Commands/VaultOrganizationCommand.cs @@ -0,0 +1,49 @@ +using AutoMapper; +using Bit.Core.Entities; +using Bit.Infrastructure.EntityFramework.Repositories; +using Bit.Seeder.Recipes; +using Bit.Seeder.Services; +using Bit.SeederUtility.Configuration; +using CommandDotNet; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; + +namespace Bit.SeederUtility.Commands; + +[Command("vault-organization", Description = "Seed an organization with users and encrypted vault data (ciphers, collections, groups)")] +public class VaultOrganizationCommand +{ + [DefaultCommand] + public void Execute(VaultOrganizationArgs args) + { + args.Validate(); + + var services = new ServiceCollection(); + ServiceCollectionExtension.ConfigureServices(services, enableMangling: args.Mangle); + var serviceProvider = services.BuildServiceProvider(); + + using var scope = serviceProvider.CreateScope(); + var scopedServices = scope.ServiceProvider; + + var manglerService = scopedServices.GetRequiredService(); + var recipe = new OrganizationWithVaultRecipe( + scopedServices.GetRequiredService(), + scopedServices.GetRequiredService(), + scopedServices.GetRequiredService>(), + manglerService); + + recipe.Seed(args.ToOptions()); + + if (!manglerService.IsEnabled) + { + return; + } + + var map = manglerService.GetMangleMap(); + Console.WriteLine("--- Mangled Data Map ---"); + foreach (var (original, mangled) in map) + { + Console.WriteLine($"{original} -> {mangled}"); + } + } +} diff --git a/util/DbSeederUtility/GlobalSettingsFactory.cs b/util/SeederUtility/Configuration/GlobalSettingsFactory.cs similarity index 90% rename from util/DbSeederUtility/GlobalSettingsFactory.cs rename to util/SeederUtility/Configuration/GlobalSettingsFactory.cs index e4ad275a0e..70f42ed560 100644 --- a/util/DbSeederUtility/GlobalSettingsFactory.cs +++ b/util/SeederUtility/Configuration/GlobalSettingsFactory.cs @@ -1,7 +1,7 @@ using Bit.Core.Settings; using Microsoft.Extensions.Configuration; -namespace Bit.DbSeederUtility; +namespace Bit.SeederUtility.Configuration; public static class GlobalSettingsFactory { @@ -20,7 +20,7 @@ public static class GlobalSettingsFactory .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true, reloadOnChange: true) - .AddUserSecrets("bitwarden-Api") // Load user secrets from the API project + .AddUserSecrets("bitwarden-Api") .AddEnvironmentVariables(); var configuration = configBuilder.Build(); diff --git a/util/DbSeederUtility/ServiceCollectionExtension.cs b/util/SeederUtility/Configuration/ServiceCollectionExtension.cs similarity index 83% rename from util/DbSeederUtility/ServiceCollectionExtension.cs rename to util/SeederUtility/Configuration/ServiceCollectionExtension.cs index 0a2288a4c2..02a0c78449 100644 --- a/util/DbSeederUtility/ServiceCollectionExtension.cs +++ b/util/SeederUtility/Configuration/ServiceCollectionExtension.cs @@ -7,16 +7,14 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; -namespace Bit.DbSeederUtility; +namespace Bit.SeederUtility.Configuration; public static class ServiceCollectionExtension { public static void ConfigureServices(ServiceCollection services, bool enableMangling = false) { - // Load configuration using the GlobalSettingsFactory var globalSettings = GlobalSettingsFactory.GlobalSettings; - // Register services services.AddLogging(builder => { builder.AddConsole(); @@ -27,9 +25,7 @@ public static class ServiceCollectionExtension services.AddSingleton, PasswordHasher>(); services.TryAddSingleton(); - // Add Data Protection services - services.AddDataProtection() - .SetApplicationName("Bitwarden"); + services.AddDataProtection().SetApplicationName("Bitwarden"); services.AddDatabaseRepositories(globalSettings); diff --git a/util/SeederUtility/Program.cs b/util/SeederUtility/Program.cs new file mode 100644 index 0000000000..74f3f57387 --- /dev/null +++ b/util/SeederUtility/Program.cs @@ -0,0 +1,22 @@ +using Bit.SeederUtility.Commands; +using CommandDotNet; + +namespace Bit.SeederUtility; + +public class Program +{ + private static int Main(string[] args) + { + return new AppRunner() + .Run(args); + } + + [Subcommand] + public OrganizationCommand Organization { get; set; } = null!; + + [Subcommand] + public VaultOrganizationCommand VaultOrganization { get; set; } = null!; + + [Subcommand] + public SeedCommand Seed { get; set; } = null!; +} diff --git a/util/DbSeederUtility/README.md b/util/SeederUtility/README.md similarity index 81% rename from util/DbSeederUtility/README.md rename to util/SeederUtility/README.md index 82cd4c528c..cde949bf5f 100644 --- a/util/DbSeederUtility/README.md +++ b/util/SeederUtility/README.md @@ -1,10 +1,10 @@ -# Bitwarden Database Seeder Utility +# Bitwarden Seeder Utility -A CLI wrapper around the Seeder library for generating test data in your local Bitwarden database. +A CLI wrapper around the Seeder library for generating test data in a Bitwarden database. ## Getting Started -Build and run from the `util/DbSeederUtility` directory: +Build and run from the `util/SeederUtility` directory: ```bash dotnet build @@ -15,6 +15,16 @@ dotnet run -- [options] ## Commands +### `organization` - Users Only (No Vault Data) + +```bash +# 100 users +dotnet run -- organization -n MyOrgNoCiphers -u 100 -d myorg-no-ciphers.com + +# 10,000 users for load testing +dotnet run -- organization -n LargeOrgNoCiphers -u 10000 -d large-org-no-ciphers.test +``` + ### `seed` - Fixture-Based Seeding ```bash @@ -22,25 +32,17 @@ dotnet run -- [options] dotnet run -- seed --list # Load the Dunder Mifflin preset (58 users, 14 groups, 15 collections, ciphers) -dotnet run -- seed --preset dunder-mifflin-full +dotnet run -- seed --preset dunder-mifflin-enterprise-full # Load with ID mangling for test isolation -dotnet run -- seed --preset dunder-mifflin-full --mangle +dotnet run -- seed --preset dunder-mifflin-enterprise-full --mangle + +dotnet run -- seed --preset stark-free-basic --mangle # Large enterprise preset for performance testing dotnet run -- seed --preset large-enterprise -dotnet run -- seed --preset dunder-mifflin-full --password "MyTestPassword1" --mangle -``` - -### `organization` - Users Only (No Vault Data) - -```bash -# 100 users -dotnet run -- organization -n MyOrg -u 100 -d myorg.com - -# 10,000 users for load testing -dotnet run -- organization -n seeded -u 10000 -d large.test +dotnet run -- seed --preset dunder-mifflin-enterprise-full --password "MyTestPassword1" --mangle ``` ### `vault-organization` - Users + Encrypted Vault Data diff --git a/util/DbSeederUtility/DbSeederUtility.csproj b/util/SeederUtility/SeederUtility.csproj similarity index 85% rename from util/DbSeederUtility/DbSeederUtility.csproj rename to util/SeederUtility/SeederUtility.csproj index f6195a6763..b0e9f7b5e4 100644 --- a/util/DbSeederUtility/DbSeederUtility.csproj +++ b/util/SeederUtility/SeederUtility.csproj @@ -5,8 +5,8 @@ net8.0 enable enable - Bit.DbSeederUtility - DbSeeder + Bit.SeederUtility + SeederUtility true 2294c6ba-7cd0-4293-a797-3882e41c61cb