Skip to content

feat(seeder): age seeded users by default - #8200

Closed
nthompson-bitwarden wants to merge 1 commit into
mainfrom
seeder/aged-users-by-default
Closed

feat(seeder): age seeded users by default#8200
nthompson-bitwarden wants to merge 1 commit into
mainfrom
seeder/aged-users-by-default

Conversation

@nthompson-bitwarden

Copy link
Copy Markdown
Contributor

🎟️ Tracking

https://bitwarden.atlassian.net/browse/QA-2310

📔 Objective

Seeded users previously fell back to the User entity's CreationDate initializer (DateTime.UtcNow), so every account looked brand-new and age-gated scenarios (e.g. the premium upsell path) could not be reproduced.

UserSeeder.Create now backdates CreationDate for every seeding path. A new nullable UserSeed.AccountAgeDays controls it: null (default) randomizes an aged date between 91 days and 3 years ago, 0 seeds today, and N seeds exactly N days ago. RevisionDate and AccountRevisionDate are left at now.

The knob is exposed through the individual CLI command (--account-age-days) and the SingleUserScene request. Org owner, bulk member, and roster paths inherit the aged default automatically.

📸 Screenshots

Seeded users previously fell back to the User entity's CreationDate
initializer (DateTime.UtcNow), so every account looked brand-new and
age-gated scenarios (e.g. the pm-32180-premium-upsell-account-age
path) could not be reproduced.

UserSeeder.Create now backdates CreationDate for every seeding path.
A new nullable UserSeed.AccountAgeDays controls it: null (default)
randomizes an aged date between 91 days and 3 years ago, 0 seeds
today, and N seeds exactly N days ago. RevisionDate and
AccountRevisionDate are left at now.

The knob is exposed through the individual CLI command
(--account-age-days) and the SingleUserScene request. Org owner,
bulk member, and roster paths inherit the aged default automatically.
@nthompson-bitwarden nthompson-bitwarden added the t:misc Change Type - ¯\_(ツ)_/¯ Prefer using other type labels label Aug 13, 2026
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed the seeder change that backdates User.CreationDate for every seeding path, the new AccountAgeDays knob threaded through UserSeed, IndividualUserOptions, the pipeline step, the CLI flag, and SingleUserScene, plus the four new factory tests. The plumbing is consistent end to end, the CLI validates negative input, and Random.Shared is safe for the parallel bulk-user paths. One question raised about a downstream interaction with device verification.

Code Review Details
  • ❓ : Aged-by-default accounts fall outside the 24-hour new-device-verification grace window in DeviceValidator, changing login behavior for existing seeder consumers
    • util/Seeder/Factories/UserSeeder.cs:64

Comment on lines +64 to +65
var ageDays = seed.AccountAgeDays ?? Random.Shared.Next(91, 1096);
user.CreationDate = DateTime.UtcNow.AddDays(-ageDays);

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.

QUESTION: Aging by default pushes every seeded account past the 24-hour new-device-verification window — was that interaction evaluated?

Details

HandleNewDeviceVerificationAsync in src/Identity/IdentityServer/RequestValidators/DeviceValidator.cs:146 short-circuits to Success only while DateTime.UtcNow - user.CreationDate < 24h, and User.VerifyDevices defaults to true (the seeder never sets it). Previously every seeded account sat inside that grace window; now none of them do. The first login still succeeds because the user has no devices yet, but a login from a second device identifier returns NewDeviceVerificationRequired and needs an OTP from email.

Same file, line 207: SendNewDeviceLoginEmail suppresses the email only for accounts under 10 minutes old, so seeded logins now also generate new-device emails they previously did not.

If that's the intended realism, a line in util/SeederUtility/README.md pointing multi-device login flows at --account-age-days 0 would save the next person the debugging. Worth noting that preset-driven seeding (util/Seeder/Pipeline/PresetLoader.cs:46) has no equivalent escape hatch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t:misc Change Type - ¯\_(ツ)_/¯ Prefer using other type labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant