Bitwarden Seeder Fixtures 指南:如何编写组织化的 JSON 测试数据 Bitwarden Seeder Fixtures 指南如何编写组织化的 JSON 测试数据【免费下载链接】serverBitwarden infrastructure/backend (API, database, Docker, etc).项目地址: https://gitcode.com/GitHub_Trending/ser/serverBitwarden 仓库中的 Seeder 工具util/Seeder通过一套分层的 JSON 数据体系为本地与测试环境批量生成数据库手工编写的Fixturefixture负责定义什么存在而 Preset 负责这些东西如何关联。本文以 fixtures.md 为主线完整讲解 Organization、Roster、Cipher 三类 fixture 的字段语义、邮箱派生与 Mangle 机制、命名规范与校验方式并结合仓库内的真实 fixture 文件和 JSON Schema帮助你从零写出可复用的测试数据。Fixture 的分层定位独立的砖块Seeder 数据体系的核心规则是Fixtures 定义什么存在Presets 定义事物之间的关系。Fixture 是彼此独立、可复用的构建单元它们之间从不互相引用一个 roster 不知道它会被配到哪个组织、哪份 cipher 文件上。唯一的组装层是 preset——它是 preset --name 命令行入口也是唯一定义跨 fixture 关系collection 分配、folder 归属、favorite 标记的层。完整分层架构见同目录的 architecture.md其中用一个数据库类比概括了各层职责Fixture 层类比数据库概念OrganizationOrganization表RosterUserGroupCollection 关联表CiphersCipher表Preset那条JOIN——挑选表并定义关系各类 fixture 按类型存放在util/Seeder/Seeds/fixtures/下的organizations/、rosters/、ciphers/三个子目录中。写任何 fixture 的第一步都是添加一行$schema指向对应的 JSON Schema 文件让编辑器获得自动校验{ $schema: ../../schemas/organization.schema.json, ... }Schema 文件位于 schemas/organization.schema.json、schemas/roster.schema.json 和 schemas/cipher.schema.json它们是字段可用性的最终事实来源source of truth。Organization fixture只有名字和域名Organization fixture 的约定极其克制——只需要name和domain两个字段。从 organization.schema.json 可以看到name、domain均为必填required: [name, domain]且minLength: 1additionalProperties: false——不允许任何额外字段比如计划类型Plan type或席位数domain的描述明确写着用于派生账单邮箱和生成 identifier。计划类型、席位等属性定义在 preset 里而不是 organization fixture 里。仓库中最小的示例见 fixtures/organizations/redwood-analytics.json全文只有三个字段{ $schema: ../../schemas/organization.schema.json, name: Redwood Analytics, domain: redwood.example }关于域名的硬性约定必须使用.example后缀RFC 2606 保留域名——保证无法解析对邮箱管道绝对安全。这一点在源码中同样得到印证OrganizationSeeder.cs 在创建组织实体时会把seed.Domain传入IManglerService.Mangle()生成数据库用的Identifier所以域名的安全性会直接影响落库数据的形态。fixtures/organizations/目录下已有 14 个现成示例dev-org.json、stark-industries.json、zero-knowledge-labs.json等可作参照。Roster fixture用户、组与集合Roster 是 fixture 三类中字段最丰富的一种描述一个组织的人员结构用户、组、集合含权限。roster.schema.json 中仅users为必填且minItems: 1groups和collections可选。用户与邮箱派生规则用户对象必填firstName和lastName可选role枚举owner、admin、user、custom默认user。Seeder 会按firstName.lastNamedomain派生邮箱——例如 roster 中FamilyMom配在域名acme.example的组织下得到的就是family.momacme.example当 Mangle数据扰码开启时同一用户会变成a1b2c3d4family.momacme.example。从源码看这一机制落在 UserSeeder.cs邮箱字段只有在Keys null即走标准加密路径时才被manglerService.Mangle(seed.Email)处理而引用解析侧EntityRegistry.cs 维护了一个UserEmailPrefixToUserId字典OrdinalIgnoreCase比较这就是按邮箱前缀查找用户的底层实现。用户可以显式设置email字段来覆盖派生地址用途是为账号提供好记的登录名。典型例子是 fixtures/rosters/dev-roles.json它给四个角色账号分别指定了ownerbw.example、adminbw.example、custombw.example、userbw.example并附带title如 Chief Executive Officer。两个关键细节即使邮箱被覆盖组和集合的引用仍按firstName.lastName前缀解析——只改变落库地址不改变引用键如果两个用户最终解析到同一个邮箱seed 会按 roster 名称直接报错失败fail。除文档强调的字段外schema 还允许以下扩展字段均有实际用例title职位如dev-roles.json中的 Software Engineerstatus组织成员状态枚举confirmed、invited、accepted、revoked默认confirmedbranch/department分组用字符串。58 人企业级 roster fixtures/rosters/dunder-mifflin.json 就是靠branch: Scranton、department: Sales之类的字段把人物按分支机构与部门组织起来的folders字符串数组uniqueItems: true用户可声明如folders: [Banking, Work]——每个名字都会为对应用户创建一个加密的 Folder 实体。dev-roles.json中 owner 声明了[Break Glass]普通用户 Uma 声明了[Work, Personal Projects]。最小 roster 与完整 roster 对照最小的 roster 是 fixtures/rosters/starter-team.json10 个用户、1 个 Everyone 组、1 个只含单个用户权限的集合{ $schema: ../../schemas/roster.schema.json, users: [ { firstName: StarterTeam, lastName: Owner, role: owner }, { firstName: StarterTeam, lastName: UserOne, role: user } ], groups: [ { name: Everyone, members: [starterteam.owner, starterteam.userone] } ], collections: [ { name: Default collection, users: [{ user: starterteam.no-mp-non-trusted, manage: true }] } ] }而 fixtures/rosters/family.json 展示了组与集合权限的完整用法三个组Everyone / Parents / Grandparents成员全部用family.mom这类前缀引用集合按组 单个用户两种方式授权collections: [ { name: Banking, groups: [{ group: Parents, manage: true }] }, { name: School, users: [ { user: family.son }, { user: family.daughter } ] } ]权限布尔量共三个readOnly、hidePasswords、manage全部默认falseschema 中显式标注了default: false。dev-roles.json展示了权限矩阵的实战形态——集合名可用/表达视觉层级如Engineering/CI Releases、Leadership/Break Glass同一集合内既可以给Leadership组readOnly: true又可以让casey.custom用户readOnly: true, hidePasswords: true同时 owner 持有manage: true。组与集合都支持可选的externalId用于目录同步/API 测试兼容。大规模 rosterdunder-mifflin.json 是一个 58 人的企业级 roster5 位 owner 级高管、15 位 admin其余为普通 user并用branchCorporate / Scranton / Stamford / Nashua与departmentSales、Accounting、Warehouse、IT……做了二维分组。写大型 roster 时可以照此结构按角色区块划分 JSON 数组每个用户带全部分组字段。Cipher fixture保险库条目Cipher fixture 描述保险库条目vault items顶层是items数组每个条目必须有type和name。标杆示例是 fixtures/ciphers/enterprise-basic.json它几乎覆盖了一切实战字段条目类型typelogin登录项、secureNote安全笔记、card卡片、identity身份档案、bankAccount银行账户、passport护照、driversLicense驾照、sshKeySSH 密钥。login 条目的常用字段{ type: login, name: Concur Travel Expense, notes: Shared Finance login for expense submission. EXAMPLE fake seeder data., reprompt: 1, login: { username: apverdant.example, password: Fake-Concur-Pass-24, totp: JBSWY3DPEHPK3PXP, uris: [{ uri: https://concursolutions.com, match: host }], passwordHistory: [ { password: Fake-AWS-Root-Prev-01, lastUsedDate: 2025-11-02T10:00:00Z } ] } }reprompt: 1表示启用主密码复验证master-password repromptenterprise-basic.json中的 AWS Root、ADP 等敏感条目都开了它uris支持match: host主机精确匹配passwordHistory记录历史密码及lastUsedDate。通用增强字段fields自定义字段数组如{ name: Account ID, value: VH-88213, type: text }type可为text或hidden隐藏字段如 API Key、恢复短语cipherEncryption: cipherKey指定条目使用 cipher key 加密模式bankAccount、card、identity、sshKey 等敏感类型在示例中普遍带此字段attachments附件数组指向attachments/目录下的 mock 文件attachments: [ { file: mock-seeder-data-expense-report-3.pdf, fileName: q3-expense-report.pdf, attachmentVersion: v1 } ]附件源文件存放在 Seeds/attachments/ 目录包含 12 个带mock-seeder-data-前缀的 PDF/TXT 文件银行对账单、护照扫描件、W-9 表格、SSH 公钥等file指向源文件名fileName是落库后的显示名attachmentVersion取值v0/v1/v2。archived: true/deleted: true示例中专门准备了一批归档与已删除条目如 Legacy VPN — Cisco AnyConnect 标记archivedDecommissioned Jenkins 标记deleted用于验证软删除与归档流程。命名规范fixtures.md 给出的命名规范是团队协作时的硬性约定元素规则示例文件名kebab-casebanking-logins.json条目名称Title case全局唯一Chase Bank Login用户引用firstName.lastNamejane.doe组织域名.exampleacme.example注意用户引用与派生邮箱的小写化差异roster 里写的是firstName.lastName保留原大小写而groups.members、collections.users.user中统一用小写前缀如starterteam.owner、family.mom解析时按OrdinalIgnoreCase匹配所以大小写不敏感但保持小写前缀是仓库内所有 fixture 的实际写法。校验$schema 构建期检查fixture 的校验有两道防线编辑器实时校验——只要文件头部有$schema行编辑器就会按对应 schema 报出字段错误如role写错枚举、additionalProperties: false下的多余字段构建期兜底——schema 违规也会在编译时被捕获dotnet build util/Seeder/Seeder.csproj建议的工作流新文件先复制最接近的现有 fixture 改字段$schema相对路径../../schemas/xxx.schema.json不能丢边写边看编辑器波浪线最后跑一次 build 确认。安全红线fixtures.md 结尾列出的三条安全原则同样必须遵守这也是整套.example域名与mock-seeder-data-*文件命名存在的根本原因只用虚构的姓名、地址绝不提交真实密码或个人身份信息PII——enterprise-basic.json中所有密码均为Fake-XXX-NN形式的占位值notes 里统一标注 EXAMPLE fake seeder data.绝不向生产数据库注入 seed 数据——Seeder 只服务于本地开发与测试环境。小结写 fixture 时可以记住这张速查表想做的事改哪里新增一个组织fixtures/organizations/下建 kebab-case JSON只写name.example域名增删人员、组、集合与权限对应fixtures/rosters/文件引用一律用firstName.lastName前缀覆盖某人登录邮箱用户对象加email字段引用前缀不变给某用户建加密文件夹用户对象加folders: [...]增删保险库条目fixtures/ciphers/文件typename必填附件放attachments/定义条目→集合/文件夹/收藏的归属不改 fixture改 presetpreset 是唯一的关系层fixture 写得干净独立、无交叉引用preset 才能自由复用它们——这正是 architecture.md 中砖块 组装说明书设计意图的落地方式。【免费下载链接】serverBitwarden infrastructure/backend (API, database, Docker, etc).项目地址: https://gitcode.com/GitHub_Trending/ser/server创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考