Ensure seeder appsettings.{env}.json can be found - #8222
Conversation
SeederUtility resolved configuration from the caller's working directory, so the appsettings files were never found when launched via dev/seed.ps1 (or anywhere but the project directory) — and they were not copied to the build output at all. Since the seeder started reading attachment storage settings from configuration, this forced everyone to hand-set connection strings in user secrets. Copy the appsettings files to the output directory and load configuration through Host.CreateApplicationBuilder conventions, anchored at the binary's directory. The environment honors ASPNETCORE_ENVIRONMENT then DOTNET_ENVIRONMENT and falls back to Development — this is a dev-only tool, so appsettings.Development.json applies out of the box and user secrets load via the project's UserSecretsId.
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE Reviewed a two-file, dev-tooling bugfix that makes Code Review DetailsNo findings. |
CommandDotNet infers an option's arity from its property: nullable types and non-default initializers are optional, but a bare int reads as required because 0 is indistinguishable from "no default assigned" (an explicit `= 0` initializer changes nothing). Since #8201 every individual seed without --account-age-days — including all of dev/seeds.json via seed.ps1 — failed with "account-age-days is required". Declare the option as int? and apply the documented default of 0 when mapping to IndividualUserOptions.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8222 +/- ##
==========================================
- Coverage 63.27% 63.27% -0.01%
==========================================
Files 2383 2383
Lines 103919 103919
Branches 9408 9408
==========================================
- Hits 65755 65753 -2
- Misses 35914 35916 +2
Partials 2250 2250 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
🎟️ Tracking
No Jira issue. Supersedes #8154 (thanks @patriksvensson — your commit is carried over with authorship intact), reworked per the feedback there from @Hinton and @justindbaur.
📔 Objective
Make the seeder find its
appsettings.{env}.jsonfiles again, without requiring everyone to hand-set connection strings in user secrets.GlobalSettingsFactoryresolved configuration from the caller's working directory, so the appsettings files were never found when launching viadev/seed.ps1(cwd isdev/) — and they were not copied to the build output at all. This became a real problem with #7953, which made the seeder read attachment storage settings from configuration: with the appsettings never loading, storage resolved to Noop and attachment fixtures failed unless the connection string was manually added to user secrets.Changes:
appsettings.json/appsettings.Development.jsonto the output directory (from Ensure appsettings.{env}.json can be found #8154).ConfigurationBuilderwithHost.CreateApplicationBuilderconventions (the modern equivalent ofHost.CreateDefaultBuilder, without building a throwaway host), anchored atAppContext.BaseDirectory.ASPNETCORE_ENVIRONMENT, thenDOTNET_ENVIRONMENT, then falls back to Development instead of Production — the seeder is a dev-only tool, soappsettings.Development.json(Azurite connection strings) applies out of the box. User secrets now load via the project's existingUserSecretsId(bitwarden-seeder-utility), the same storedev/setup_secrets.ps1populates.Verified end to end: from
dev/with no environment variables set,preset --name individual.encryption-modes(the attachments fixture) seeds successfully against a local SqlServer + Azurite — previously it failed fast with Noop attachment storage.Also includes a one-commit fix for #8201:
--account-age-dayswas declared as a bareint, which CommandDotNet treats as required (0 is indistinguishable from "no default"), breaking everyindividualseed — includingdev/seed.ps1. Declared asint?with the documented default of 0 applied inToOptions().