Skip to content

Ensure seeder appsettings.{env}.json can be found - #8222

Merged
Hinton merged 2 commits into
mainfrom
hinton/seeder-fix
Aug 17, 2026
Merged

Ensure seeder appsettings.{env}.json can be found#8222
Hinton merged 2 commits into
mainfrom
hinton/seeder-fix

Conversation

@Hinton

@Hinton Hinton commented Aug 17, 2026

Copy link
Copy Markdown
Member

🎟️ 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}.json files again, without requiring everyone to hand-set connection strings in user secrets.

GlobalSettingsFactory resolved configuration from the caller's working directory, so the appsettings files were never found when launching via dev/seed.ps1 (cwd is dev/) — 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:

  • Copy appsettings.json / appsettings.Development.json to the output directory (from Ensure appsettings.{env}.json can be found #8154).
  • Replace the hand-rolled ConfigurationBuilder with Host.CreateApplicationBuilder conventions (the modern equivalent of Host.CreateDefaultBuilder, without building a throwaway host), anchored at AppContext.BaseDirectory.
  • The environment honors ASPNETCORE_ENVIRONMENT, then DOTNET_ENVIRONMENT, then falls back to Development instead of Production — the seeder is a dev-only tool, so appsettings.Development.json (Azurite connection strings) applies out of the box. User secrets now load via the project's existing UserSecretsId (bitwarden-seeder-utility), the same store dev/setup_secrets.ps1 populates.

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-days was declared as a bare int, which CommandDotNet treats as required (0 is indistinguishable from "no default"), breaking every individual seed — including dev/seed.ps1. Declared as int? with the documented default of 0 applied in ToOptions().

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.
patriksvensson
patriksvensson previously approved these changes Aug 17, 2026
@Hinton Hinton added the t:bugfix Change Type - Bugfix label Aug 17, 2026
@Hinton
Hinton marked this pull request as ready for review August 17, 2026 10:11
@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed a two-file, dev-tooling bugfix that makes SeederUtility resolve its appsettings.{env}.json files. GlobalSettingsFactory now builds configuration through Host.CreateApplicationBuilder anchored at AppContext.BaseDirectory instead of the caller's working directory, and the csproj copies appsettings.json / appsettings.Development.json to the build output. Configuration precedence (appsettings → environment-specific appsettings → user secrets → environment variables) is preserved by the host defaults, and user secrets still resolve through the project's existing UserSecretsId since the environment falls back to Development. No production code paths, no secrets, and no dependency graph changes are involved — packages.lock.json is untouched because Microsoft.Extensions.Hosting already flows in transitively via SharedWeb.

Code Review Details

No 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

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.27%. Comparing base (d95a04d) to head (c47a85f).

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.
📢 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.

@Hinton
Hinton merged commit 9381b17 into main Aug 17, 2026
46 checks passed
@Hinton
Hinton deleted the hinton/seeder-fix branch August 17, 2026 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t:bugfix Change Type - Bugfix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants