
Bitwarden SeederUtility 深度指南用 CLI 为数据库注入组织、用户与 Stripe 测试订阅【免费下载链接】serverBitwarden infrastructure/backend (API, database, Docker, etc).项目地址: https://gitcode.com/GitHub_Trending/ser/serverSeederUtility 是 Bitwarden 仓库中util/Seeder库的命令行封装用于在 Bitwarden 数据库中批量生成可控的测试数据——组织含用户、分组、集合、密码条、独立个人用户、以及基于 JSON 预设的可复现场景。读完本文你将掌握全部三个子命令的完整参数与取值约束、Stripe 测试模式计费的开通前提与失败边界并能从源码层面理解参数校验、依赖注入延迟初始化等实现细节。工具定位与运行架构SeederUtility 基于 CommandDotNet 构建入口为 Program.cs其Main方法通过AppRunnerProgram注册了三个[Subcommand]子命令organization、preset、individual分别对应 OrganizationCommand、PresetCommand 与 IndividualCommand。每个命令的执行路径一致调用args.Validate()完成参数校验非法参数抛出ArgumentException通过 SeederServiceFactory.Create 构造一个独立的ServiceCollection把 Seeder 库所需的DatabaseContext、IMapper、IPasswordHasherUser、IManglerService、ILicensingService、IAttachmentStorageService、ISeederLicenseSigner等解析进作用域委托给 Seeder 库的 Recipe 执行落库——organization/preset走OrganizationRecipe.SeedAsyncindividual走IndividualUserRecipe.SeedAsync以ConsoleOutput.PrintRow输出结果键值对如Organization、Owner、Password、各类计数。两个值得注意的源码设计计费依赖延迟构造SeederServiceFactory 中BillingInitializer被包成一个FuncIStripeBillingInitializer闭包只有真正传了--stripe-billing的命令才会触达IOrganizationBillingService - IBraintreeGateway, IStripeAdapter, ...这条 DI 图避免每条命令都构建计费子系统统一错误退出码三个命令都catch (Exception ex) when (ex is ArgumentException or InvalidOperationException)打印Error: ...后Environment.Exit(1)因此脚本化调用可以依赖退出码判断成败。快速开始在util/SeederUtility目录下构建并运行dotnet build dotnet run -- command [options]登录凭据约定后续所有命令通用所有被种子化的用户默认密码为asdfasdfasdf可用--password覆盖组织预设的组织者邮箱默认为ownerdomain可用--owner-email覆盖个人预设的邮箱来自预设内的user.email字段对individual命令提供--first-name/--last-name时邮箱为{first}.{last}individual.example不提供姓名时生成随机 Faker 身份并自动启用 mangling源码见 IndividualArgs.Validate。organization自由控制组织形态当预设目录无法满足需求时使用——例如需要一个完全没有库数据的组织所有预设都包含 ciphers。命令定义为 OrganizationCommand“Seed an organization with users and optional vault data (ciphers, collections, groups)”。常用示例继承自官方 README# 带库数据的小组织 dotnet run -- organization -n SmallOrg -d small.example -u 3 -c 10 -g 5 -o Traditional --mangle # 仅用户无库数据 dotnet run -- organization -n MyOrgNoCiphers -u 100 -d myorg-no-ciphers.example # 自定义密码与计划类型 dotnet run -- organization -n CustomOrg -d custom.example -u 10 -c 100 -g 3 --password MyTestPassword1 --plan-type teams-annually完整参数表源自 OrganizationArgs.cs参数说明与默认值-n, --name组织名称必填-u, --users用户数最小 1-d, --domain用户邮箱域必须以.example结尾RFC 2606 保留域--claimed-domain已验证claimed域可重复传入多个-c, --ciphers密码条数量默认 0无库数据-g, --groups分组数量默认 0--collections集合数量默认 0使用密度档案时必需--density密度档案balanced、highPerm、highCollection、broad、minimal、groupHeavy、sparse-m, --mix-user-statuses真实状态混合85% confirmed、invited/accepted/revoked 各 5%默认 true需 ≥10 用户-o, --org-structure集合结构Traditional、Spotify、Modern、Government、SchoolDistrict、Healthcare、Startup-r, --region人名地理区域NorthAmerica、Europe、AsiaPacific、LatinAmerica、MiddleEast、Africa、Global--mangle启用 mangling 做测试隔离每次运行生成唯一的 ID/邮箱/标识符--password所有账户密码默认asdfasdfasdf--owner-email覆盖组织者邮箱必须是合法邮箱且 User 表中不存在--plan-typefree、teams-monthly、teams-annually、enterprise-monthly、enterprise-annually、teams-starter、families-annually默认enterprise-annually--kdf-iterationsKDF 迭代次数默认 5000最小 5000生产级 e2e 测试建议 600000--auto-confirm-users邀请用户无需人工审批自动确认--allow-admin-collection-access允许管理员/所有者访问所有集合项--limit-item-deletion仅 Can Manage 权限成员可删除条目--limit-collection-creation/--limit-collection-deletion集合创建/删除仅限管理员/所有者--stripe-billing/--skip-trial/--trial-daysStripe 计费选项见下文参数校验规则OrganizationArgs.Validate 在执行前强制以下约束违反即报Error:并以退出码 1 终止Users至少为 1Domain必须以.example结尾例如myorg.example--structure、--region、--density均为闭集枚举非法值给出允许列表提示--plan-type必须可被PlanFeatures.Parse解析--kdf-iterations小于 5000 被拒绝--stripe-billing与--plan-type free互斥——“The Free plan has no Stripe subscription”--owner-email必须包含。individual独立个人用户用于需要可预测邮箱的命名用户或带生成式个人库的场景——individual 预设只会创建无库数据的裸账户。命令见 IndividualCommand。# 命名用户可预测邮箱 (john.doeindividual.example) dotnet run -- individual --subscription free --first-name John --last-name Doe # Premium 命名用户带个人库约 75 条 ciphers、5 个文件夹 dotnet run -- individual --subscription premium --first-name Jane --last-name Smith --vault # 随机姓名——自动启用 mangling dotnet run -- individual --subscription premium --vault # 自建实例——签署并写入 license 文件使 premium 状态被识别 dotnet run -- individual --subscription premium --first-name Jane --last-name Smith --self-hosted # 老化账户——CreationDate 回拨 365 天 dotnet run -- individual --subscription free --account-age-days 365参数要点源自 IndividualArgs.cs--subscription仅接受free或premium大小写不敏感--first-name/--last-name必须成对出现否则报错 “Provide both ... or neither”--vault生成约 75 条个人 ciphers 与文件夹--kdf-iterations默认 5000、最小 5000--account-age-days不得为负默认 0 即当天--email可显式指定邮箱。自建实例的 license 机制加--self-hosted才会为 premium 状态签署并写入 license 文件只有当licenseCertificatePath与licenseCertificatePassword指向持有 Bitwarden开发版licensing 密钥的 PFX 时才实际写 license——生产证书被刻意不信任。找不到匹配证书时seeder 记录警告并跳过 license 生成账户依然创建只是 premium 状态不被识别。账户老化的边界--account-age-days N只回拨CreationDate各修订时间戳revision dates仍停留在种子化当时——从源码结构看这保持了时间线的一致性避免修订日期早于创建日期的矛盾数据。preset基于内嵌 JSON 目录的可复现场景预设是精选的 JSON fixture包含特定的用户、分组、集合与 cipher 关系——每次运行都是同一份数据适合需要已知、可复现场景而非随机生成数据的场合。# 列出可用预设 dotnet run -- preset --list # 日常开发预设带易记的角色登录 dotnet run -- preset --name dev.playground # QA 预设已知用户与关系 dotnet run -- preset --name qa.enterprise-basic --mangle # 性能测试的规模化预设 dotnet run -- preset --name scale.md-balanced-sterling-cooper --mangle # 个人用户预设 dotnet run -- preset --name individual.premium --mangle命令路由逻辑PresetCommand.ExecuteAsync通过PresetCatalogService.IsIndividualPreset判断预设属于个人还是组织分别走IndividualUserRecipe或OrganizationRecipe。--list支持--output text|json两种格式JSON 输出会按organization/individual分组并附Available Fixtures清单。组织预设接受以下覆盖参数PresetArgs.cs--mangle每次运行生成唯一 ID、邮箱与标识符使同一预设可反复种子化--org-name覆盖组织显示名--owner-email覆盖所有者登录邮箱默认ownerpreset-domain--kdf-iterations覆盖预设中的 KDF 值--stripe-billing/--skip-trial/--trial-days与organization命令完全一致的 Stripe 选项。两个覆盖项可与--mangle组合使用。个人预设不支持--stripe-billing源码会直接抛出 “Only organization presets can be billed today”PresetCommand.cs 第 28–33 行。完整预设目录见 presets.md不知道跑什么命令时可先查 Scenarios 指南它把常见任务映射到具体命令。Stripe 测试计费让 Billing 页面真正可用默认情况下种子化组织没有任何计费数据网关字段保持 NULLseeder 对 Stripe零调用。对组织执行--stripe-billingorganization或preset后会在 Stripe测试环境创建真实 customer 与 subscription使座位自动扩容、订阅管理与升级流程表现得和手工创建的组织一样——否则 Billing → Subscription 页面会挂起无从测试。计费参数三个选项由 StripeBillingArgs 统一校验与映射参数适用范围效果--stripe-billingorganization、preset为组织创建 Stripe customer subscription。与--plan-type free及个人预设互斥--skip-trial配合--stripe-billing订阅直接active而非trialing立即以pm_card_visa测试卡扣费--trial-days N配合--stripe-billing试用期天数1–30默认 30与--skip-trial互斥# 30 天试用期的 Teams 组织订阅页面真正可用 dotnet run -- organization -n Billing Test -u 3 -d billingtest.example --plan-type teams-monthly --stripe-billing --mangle # 预设组织无试用期的已付费订阅 dotnet run -- preset --name qa.enterprise-basic --stripe-billing --skip-trial --mangle成功时输出会多出两行StripeCustomer : cus_… StripeSubscription : sub_…前提条件在bitwarden-seeder-utility的 user secrets 中配置globalSettings:stripe:apiKey且必须是测试模式密钥sk_test_…——生产密钥会被直接拒绝该工具永不触碰生产计费globalSettings:pricingUri必须已设置以便解析计划定价。appsettings.Development.json 已内置该值https://billingpricing.qa.bitwarden.pw因此必须ASPNETCORE_ENVIRONMENTDevelopment才能生效globalSettings:selfHosted必须为false——自建模式下 Pricing Service 永远不会被调用无法解析任何计划。三项检查在创建任何实体之前完成配置错误的 opt-in 会以报错信息和退出码 1 失败而不是留下半个种子化组织。环境解析逻辑见 GlobalSettingsFactory它同时尊重ASPNETCORE_ENVIRONMENT与DOTNET_ENVIRONMENT且回落到 Development 而非 Production确保本地开发时appsettings.Development.json生效配置文件从二进制所在目录AppContext.BaseDirectory解析与调用者工作目录无关。已知边界Caveats种子化的 Teams 与 Enterprise 组织带UseSecretsManager 1且SmSeats为 NULL只有SmSeats有值时 Secrets Manager 才计入订阅因此这些组织在数据库里置了标志位但 Stripe 侧没有对应行项目计费发生在数据库提交之后。若此时 Stripe 拒绝请求密钥过期、网络故障组织已经提交命令以非零退出码结束并打印 Stripe 错误及“已写穿的”网关 ID——customer 创建前失败则两者皆 NULL订阅创建中失败则会留下真实的GatewayCustomerId。重跑前请检查错误信息中的实际状态并取消孤儿 Stripe customer销毁本地数据库不会取消 Stripe 侧订阅测试模式订阅约 90 天后自动取消。延伸阅读路径参数到选项的映射OrganizationArgs.ToOptions()生成OrganizationVaultOptionsIndividualArgs.ToOptions()生成IndividualUserOptions均直接驱动 util/Seeder 库的 Recipe预设目录与 fixture 清单util/Seeder/Seeds/docs/presets.md任务导向的命令映射util/Seeder/Seeds/docs/scenarios/README.mdAPI 侧对应的种子化服务util/SeederApi 提供 HTTP 形式的同等能力可与本 CLI 对照理解同一套 Recipe 的两种消费方式。【免费下载链接】serverBitwarden infrastructure/backend (API, database, Docker, etc).项目地址: https://gitcode.com/GitHub_Trending/ser/server创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考