拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Bytebase Store 层 WorkloadIdentityConfig 持久化验证:protojson 与 PostgreSQL JSONB 的零改动兼容机制

Bytebase Store 层 WorkloadIdentityConfig 持久化验证protojson 与 PostgreSQL JSONB 的零改动兼容机制【免费下载链接】bytebaseDatabase governance built for humans and agents — controlling changes and access across every major database.项目地址: https://gitcode.com/GitHub_Trending/by/bytebase导读本文围绕 Bytebase 后端 Store 层的WorkloadIdentityConfig验证任务展开核心结论是借助 Protocol Buffers 的protojson序列化机制与 PostgreSQL JSONB 列的自描述特性Store 层对 WORKLOAD_IDENTITY 类型主体principal的配置读写无需任何代码改动即可自动兼容。读完本文你将掌握 Bytebaseprincipal.profileJSONB 列的读写调用链、UserMessage结构体的数据流、以及如何用测试验证一个 proto 新字段在既有存储路径上的端到端生效。任务背景WORKLOAD_IDENTITY 主体类型的引入Bytebase 将访问主体principal划分为三类定义于 proto/store/store/user.protoEND_USER人类用户WORKLOAD_IDENTITY外部 CI/CD 工作负载身份如 GitHub Actions、GitLab CI 通过 OIDC 换取临时凭证SERVICE_ACCOUNT调用 Bytebase OpenAPI 的外部服务。为支持 WORKLOAD_IDENTITY 主体需要为其携带一份 OIDC 配置签发者、受众、subject 匹配规则等即WorkloadIdentityConfig。Task 6 的核心问题非常聚焦在不改动 Store 层任何业务代码的前提下这份配置能否随既有用户档案UserProfile读写机制自动持久化验证结果是肯定的。验证结论总览四个关键检查点全部通过关联设计文档 task6-store-layer-verification.md 记录了 Store 层四个关键位置的逐一核验全部标记为无需改动检查点位置结论UserMessage结构体Profile *storepb.UserProfile字段✅ 无需改动listUserImpl读取函数扫描profile列并用 protojson 反序列化✅ 无需改动CreateUser创建函数nil 初始化后 protojson 序列化入库✅ 无需改动UpdateUser更新函数profile 非 nil 时整体序列化覆盖✅ 无需改动核心机制protojson 与 JSONB 列的双向自动编解码整个验证成立的根基是 Bytebase Store 层统一采用Protocol Buffers 的 JSON 映射protojson来读写 PostgreSQL 的 JSONB 列而不是手写逐字段的 JSON 转换。这条约定贯穿了所有 principal 相关读写路径。读取路径listUserImpl 与 scanPrincipalRow在 backend/store/principal.go 的listUserImpl中SQL 查询将principal.profile列扫描进profileBytes随后profile : storepb.UserProfile{} if err : common.ProtojsonUnmarshaler.Unmarshal(profileBytes, profile); err ! nil { return nil, err } userMessage.Profile profile同样scanPrincipalRowbackend/store/principal.go作为UpdateUser、UpdateUserMFAConfigIfPending等路径共用的行扫描器也以完全相同的方式反序列化 profile。这意味着只要UserProfileproto 消息新增了字段反序列化结果就会自动携带该字段读取侧零改动。写入路径CreateUser 与 UpdateUser创建用户时backend/store/principal.go先做 nil 兜底初始化再整体序列化if create.Profile nil { create.Profile storepb.UserProfile{} } profileBytes, err : protojson.Marshal(create.Profile)随后INSERT INTO principal (..., profile) VALUES (..., ?)以 JSONB 形式落库。因此只要调用方在create.Profile.WorkloadIdentityConfig中填好配置序列化时自动包含无需 Store 层感知。更新用户时backend/store/principal.goprofile 采用整体覆盖策略if v : patch.Profile; v ! nil { profileBytes, err : protojson.Marshal(v) if err ! nil { return nil, err } set.Comma(profile ?, profileBytes) }即更新 WorkloadIdentityConfig 完全复用既有的 profile 更新通道——调用方构造携带新配置的UserProfile补丁即可Store 层只负责序列化整块 JSONB 并覆盖。UserProfile 与 WorkloadIdentityConfig 的消息定义验证所依据的 proto 定义位于 proto/store/store/user.proto。UserProfile承载用户档案message UserProfile { google.protobuf.Timestamp last_login_time 1; google.protobuf.Timestamp last_change_password_time 2; // The source indicates where the user comes from. For now we support Entra ID SCIM sync, so the source could be Entra ID. string source 3; reserved 4; // The workspace resource ID the user last logged into. string last_login_workspace 5; }WorkloadIdentityConfig是独立的 OIDC 配置消息也是验证的核心数据载体message WorkloadIdentityConfig { enum ProviderType { PROVIDER_TYPE_UNSPECIFIED 0; GITHUB 1; GITLAB 2; OIDC 3; } ProviderType provider_type 1; string issuer_url 2; // OIDC issuer URL repeated string allowed_audiences 3; // 令牌校验的允许受众 string subject_pattern 4; // 匹配令牌 subject 声明 string jwks_url 5; // 可选 JWKS 端点为空时用 issuer_url 做 OIDC discovery }说明原验证文档描述的UserProfile中内嵌workload_identity_config 4字段属于该任务进行时的中间状态从当前仓库源码看该字段位置已标记为reserved 4WorkloadIdentityConfig演进为独立消息且工作负载身份已拆分到独立数据表见下文演进章节。这恰好从侧面印证了 protojson 机制的健壮性——无论字段如何迁移JSON 映射始终自描述。数据库存储格式JSONB 中的 camelCase 细节WorkloadIdentityConfig落库于principal.profileJSONB 列文档给出了完整存储样例{ lastLoginTime: 2024-12-11T10:00:00Z, lastChangePasswordTime: 2024-12-11T09:00:00Z, source: , workloadIdentityConfig: { providerType: PROVIDER_GITHUB, issuerUrl: https://token.actions.githubusercontent.com, allowedAudiences: [https://github.com/myorg], subjectPattern: repo:myorg/myrepo:ref:refs/heads/main } }一个必须牢记的实操细节protojson 对字段名使用 camelCase 而非 proto 中的 snake_case。例如workload_identity_config在 JSONB 中写作workloadIdentityConfigprovider_type写作providerType。如果你直接在 SQL 或脚本中按 snake_case 键名查询/修改 JSONB将无法命中数据——这也是 Store 层始终用 protojson 而不是手写 JSON 的根本原因。仓库中ConsumeRecoveryCodebackend/store/principal.go等函数在 SQL 层直接操作mfa_config-recoveryCodes时同样显式注释了protojson 的拼写这一约束可见该约定是 Store 层的全局规则。测试验证字段可访问性与 CRUD 通道原验证文档新增了三个测试并全部通过TestWorkloadIdentityConfigInUserMessage验证 WorkloadIdentityConfig 可通过UserMessage.Profile访问TestCreateUserMessageWithWorkloadIdentityConfig验证CreateUser能携带 WorkloadIdentityConfigTestUpdateUserMessageWithWorkloadIdentityConfig验证UpdateUser能完成配置更新。在当前仓库中对应的持久化测试演进为 backend/store/workload_identity_test.go覆盖WorkloadIdentityMessage、CreateWorkloadIdentityMessage、UpdateWorkloadIdentityMessage三者的 Config 字段例如config : storepb.WorkloadIdentityConfig{ ProviderType: storepb.WorkloadIdentityConfig_GITHUB, IssuerUrl: https://token.actions.githubusercontent.com, AllowedAudiences: []string{https://github.com/myorg}, SubjectPattern: repo:myorg/myrepo:ref:refs/heads/main, }运行验证方式在仓库根目录执行go test ./backend/store/ -run TestWorkloadIdentity -v原文档给出的通过输出形态为ok github.com/bytebase/bytebase/backend/store配合 gofmt 与 golangci-lint 零告警共同构成了验证任务的完成判据。从验证到落地当前仓库的存储演进从当前仓库源码结构看该验证任务的结论已被后续任务继承并进一步演进——工作负载身份不再仅作为 END_USER 档案的内嵌 JSONB 段而是拥有独立的表结构与 Store 层实现建表迁移脚本 backend/migrator/migration/3.16/0000##split_principal_table.sql 将 principal 表拆分为 principal仅 END_USER、service_account、workload_identity 三张表其中workload_identity表以config jsonb NOT NULL DEFAULT {}存储WorkloadIdentityConfig并附注释标明其对应 proto/store/store/user.proto 中的消息Store 层 CRUDbackend/store/workload_identity.go 提供WorkloadIdentityMessage、GetWorkloadIdentityByEmail、ListWorkloadIdentities、CreateWorkloadIdentity、UpdateWorkloadIdentity、DeleteWorkloadIdentity软删除等完整能力其中邮箱格式约束为{name}{project-id}.workload.bytebase.com或{name}workload.bytebase.com编解码延续独立表的读写依然复用了同一套 protojson 机制——CreateWorkloadIdentity用protojson.Marshal(create.Config)写入读取时用common.ProtojsonUnmarshaler.Unmarshal(configBytes, config)还原与 Task 6 验证的机制完全同源。API 层的配置校验闭环Store 层只负责持久化配置合法性由 API 层把关。在 backend/api/v1/workload_identity_service.go 的validateWorkloadIdentityConfig中provider_type必须为 GITHUB / GITLAB / OIDC 之一issuer_url必填并通过wif.ValidateIssuerURL校验jwks_url可选提供时需通过wif.ValidateJWKSURLallowed_audiences非空且不允许空字符串subject_pattern通过wif.ValidateSubjectPattern校验。该函数与 backend/plugin/idp/wif/wif.go 中的校验实现共同构成了API 校验 → Store 持久化 → 登录换取凭证的完整链路与 Task 6 的 Store 层验证结果衔接。结论与后续步骤Task 6 的验证给出了一个可复用的工程结论在 protojson JSONB 的持久化架构下为 proto 消息新增字段不需要改动任何存储层代码只需保证读写两侧使用同一套 proto 定义与编解码器。验证通过判据为四条代码编译无错误、全部测试通过、golangci-lint 零问题、gofmt 已格式化。原文档规划的后续步骤Task 8UserService 层 workload identity CRUD API在仓库中亦已落地体现在 backend/api/v1/workload_identity_service.go 的CreateWorkloadIdentity/GetWorkloadIdentity/ListWorkloadIdentities/UpdateWorkloadIdentity/DeleteWorkloadIdentity/UndeleteWorkloadIdentity六个 RPC 以及 backend/tests/login_audit_test.go、backend/api/v1/workload_identity_service_test.go 等集成测试。对后续开发者而言若要新增类似的可配置主体字段照搬这套proto 字段扩展 protojson 编解码 JSONB 落库 API 校验的模式即可。【免费下载链接】bytebaseDatabase governance built for humans and agents — controlling changes and access across every major database.项目地址: https://gitcode.com/GitHub_Trending/by/bytebase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门