Backstage v1.17.0-next.0 版本速览:deepVisibility 配置可见性、OpenAPI 请求校验与破坏性变更解析
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
本篇指南以 Backstage 官方发布说明 docs/releases/v1.17.0-next.0-changelog.md 为骨架,深入解读该预发布版本(next.0)中最值得开发者关注的三大核心变化:config-loader 新增的deepVisibility模式关键字、基于@backstage/backend-openapi-utils的后端 OpenAPI 请求校验落地,以及plugin-catalog-backend-module-unprocessed的破坏性导出重命名。读完本文,你将理解这些变更的动机、底层实现机制、对存量项目的影响,以及如何安全升级迁移。
版本背景:next.0 发布说明的阅读方式
v1.17.0-next.0是 Backstage v1.17.0 正式发布前的第一个预发布(next)版本,用于在正式发布前收集反馈、验证变更。这类 changelog 的典型特征是:
- Minor Changes:包含新特性,是升级时需要重点关注的增量变化;
- Patch Changes:多数为依赖升级(Updated dependencies)与小的 bug 修复,例如本版本中
core-app-api修复了navigate分析事件被错误归属到根路由插件的问题(9ae4e7e63836),search-backend-node修复了 Lunr 搜索引擎因忽略无效元数据位置而导致高亮失败的问题(e3e9bc10298b); - BREAKING标记:明确标注的破坏性变更,升级时必须处理。
本文聚焦其中三个具备实质技术内容的变化点展开。
一、config-loader 1.4.0:新增 deepVisibility 配置可见性关键字
@backstage/config-loader从1.3.x升级到1.4.0-next.0,其核心新特性是引入了deepVisibility这个 JSON Schema 关键字(变更号cd514545d1d0)。
1.1 背景:Backstage 的配置可见性机制
在 Backstage 中,配置项有三类可见性(见 packages/config-loader/src/schema/types.ts):
export const CONFIG_VISIBILITIES = ['frontend', 'backend', 'secret'] as const; export type ConfigVisibility = 'frontend' | 'backend' | 'secret'; export const DEFAULT_CONFIG_VISIBILITY: ConfigVisibility = 'backend';frontend:配置会被打包进前端 bundle,暴露给浏览器(如app.baseUrl);backend:仅后端可见,默认值;secret:敏感配置,前端不可见,且后端在输出/导出时会被脱敏处理。
在引入deepVisibility之前,为某个对象下的所有子字段设置secret/frontend可见性,需要在每个叶子节点上重复标注@visibility secret,一旦新增字段忘记标注,就会退化为默认的backend,可能造成敏感信息外泄到前端,或者期望暴露给前端的字段意外缺失。
1.2 deepVisibility 的用法
deepVisibility的作用是:在对象层级声明一个默认可见性,并递归应用到其所有后代字段,同时尊重子节点已有的显式可见性标注,或子节点自身的deepVisibility覆盖。
官方示例——为一个对象及其所有子字段批量强制默认可见性为secret:
export interface Config { /** * Enforces a default of `secret` instead of `backend` for this object. * @deepVisibility secret */ mySecretProperty: { type: 'object'; properties: { secretValue: { type: 'string'; }; verySecretProperty: { type: 'string'; }; }; }; }1.3 禁止的用法:不允许用 deepVisibility 降级暴露
出于安全考虑,deepVisibility不允许将子节点可见性"提升"到比继承值更开放的级别。官方给出的反面示例中,父级声明@deepVisibility secret后,子字段frontendUrl试图用@visibility frontend将其重新暴露给前端,这是不允许的:
export interface Config { /** * Set the top level property to secret, enforcing a default of `secret` instead of `backend` for this object. * @deepVisibility secret */ mySecretProperty: { type: 'object'; properties: { frontendUrl: { /** * We can NOT override the visibility to reveal a property to the front end. * @visibility frontend */ type: 'string'; }; verySecretProperty: { type: 'string'; }; }; }; }1.4 源码级原理:编译与过滤两个阶段
从源码结构看,deepVisibility的完整实现横跨配置 schema 的编译与过滤两个阶段,位于 packages/config-loader/src/schema/compile.ts 与 packages/config-loader/src/schema/filtering.ts。
编译阶段(compile.ts):
- 通过 AJV 注册
deepVisibility关键字,其metaSchema的枚举被刻意限制为['frontend', 'secret']——不允许backend。源码注释解释了原因:禁止backend深度可见性,是为了防止"权限逃逸"(permission escaping),即避免出现deepVisibility secret -> backend -> frontend或deepVisibility secret -> backend -> visibility frontend这类逐级降级再重新暴露的链条(见 compile.ts); - 校验时,把每个设置了
deepVisibility的数据路径记录进deepVisibilityByDataPath映射表; - 遍历合并后的 schema 时,子节点若未显式声明,则继承父节点的
deepVisibility(schema[inheritedVisibility] ??= schema?.deepVisibility ?? parentSchema?.[inheritedVisibility],见 compile.ts); - 对同一路径下同时出现
frontend与secret冲突的情况直接抛错:Config schema visibility is both 'frontend' and 'secret' for <path>(见 compile.ts)。
过滤阶段(filtering.ts):filterByVisibility在递归遍历配置数据时,先取当前路径的显式可见性(visibilityByDataPath),否则取继承值;随后用deepVisibilityByDataPath计算"新的继承可见性"传递给子节点——即"遇到不同的 deepVisibility 之前,用它作为所有后代的默认可见性"(见 filtering.ts)。
测试用例印证(compile.test.ts)覆盖了四类场景:
- 父级
deepVisibility: 'secret'时,未标注的子节点(a、c、数组d及其元素)全部继承为secret,而显式标注visibility: 'secret'的b保持 secret,显式标注visibility: 'backend'的字段被尊重; - 子节点试图以
frontend覆盖继承的secret→ 抛错; - 子节点设置不同的
deepVisibility→ 抛错; - 同一 schema 节点同时声明
deepVisibility与冲突的visibility→ 抛错。
1.5 实践建议
对于插件作者:如果某个配置对象整体属于敏感信息(例如第三方系统的 token 集合),直接在对象上标注@deepVisibility secret,即可避免遗漏叶子字段带来的泄露风险;但注意不要试图用它"降级"已有安全标注。
二、后端 OpenAPI 请求校验落地:catalog/search/todo 三个后端同时启用
本次发布中,三个后端插件同时升级:
@backstage/plugin-catalog-backend@1.12.0-next.0@backstage/plugin-search-backend@1.4.0-next.0@backstage/plugin-todo-backend@0.2.0-next.0
它们的 Minor Changes 均指向同一变更号ebeb77586975:现在通过@backstage/backend-openapi-utils基于 OpenAPI schema 执行请求校验,非法输入(例如本应为数字却传了字符串"a")的错误响应可能发生变化。
2.1 backend-openapi-utils 0.0.3:新增 createRouter 方法
@backstage/backend-openapi-utils@0.0.3-next.0的 Patch Changes 披露了两件事:
- 新增
createRouter方法,用于生成一个基于你的 OpenAPI spec 进行请求校验的 express router; - 修复了查询参数类型解析的一个 bug。
从 packages/backend-openapi-utils/src/stub.ts 的实现可以看到,createRouterWithValidation的核心机制:
- 基于
express-promise-router创建 router; - 挂载
express-openapi-validator中间件,默认配置为validateRequests.coerceTypes: false(不隐式做类型转换,所以"a"不会被强转成数字,而是校验失败)、allowUnknownQueryParameters: false、validateResponses: false; - 任何来自校验中间件的错误都会被转换为
@backstage/errors中的InputError(见 stub.ts); - 同时暴露
OPENAPI_SPEC_ROUTE路由,通过openapi-merge把当前 spec 以 JSON 形式提供出去,便于开发者直接在运行时查看该插件的 OpenAPI 文档。
对外公开的两个工厂函数createValidatedOpenApiRouter与createValidatedOpenApiRouterFromGeneratedEndpointMap分别返回基于文档类型或生成端点映射的类型化 router(ApiRouter/TypedRouter)。TypedRouter在 router.ts 中定义,为get/post/put/delete提供了按 EndpointMap 推导的请求/响应类型——这意味着调用方在编译期就能得到入参与返回值的类型检查。
2.2 生成物:repo-tools 的 schema openapi generate 升级
配套地,@backstage/repo-tools@0.3.3-next.0的schema openapi generate命令(ebeb77586975)被更新为生成一个可直接导入使用的默认 router。生成逻辑位于 packages/repo-tools/src/commands/package/schema/openapi/generate/server.ts,它会在generated/router.ts中写出:
import {createValidatedOpenApiRouterFromGeneratedEndpointMap} from '@backstage/backend-openapi-utils'; import {EndpointMap} from './apis'; export const spec = { /* ... */ } as const; export const createOpenApiRouter = async ( options?: Parameters<typeof createValidatedOpenApiRouterFromGeneratedEndpointMap>['1'], ) => createValidatedOpenApiRouterFromGeneratedEndpointMap<EndpointMap>(spec, options);而 catalog-backend 的生成产物正是使用这一模式:见 plugins/catalog-backend/src/schema/openapi/generated/router.ts(spec 声明为openapi: '3.1.0')与文件末尾导出的createOpenApiRouter(router.ts)。
2.3 对开发者的影响与升级注意点
- 错误响应格式变化:非法输入的响应体由各插件自行拼装的错误信息,变为统一的
InputError(HTTP 400)。如果前端或其他调用方依赖旧的错误响应结构,需要同步适配; - 查询参数更严格:
allowUnknownQueryParameters: false意味着未在 OpenAPI spec 中声明的查询参数将被拒绝;coerceTypes: false意味着?limit="abc"这类本应报错的请求不再被静默转换; - 如何平滑迁移:升级插件前,先用
backstage-repo-tools package schema openapi generate确认你的插件 spec 与生成代码一致(仓库中的校验脚本见 packages/repo-tools/src/commands/package/schema/openapi/validate.ts),再回归测试关键 API 的合法与非法入参。
三、破坏性变更:UnprocessedEntites 修正为 UnprocessedEntities
@backstage/plugin-catalog-backend-module-unprocessed@0.2.0-next.0带来本次发布中唯一明确的BREAKING变更(5156a94c2e2a):
修正导出模块中的拼写错误,
UnprocessedEntites需改名为UnprocessedEntities。
这意味着所有import { UnprocessedEntitesModule } from '@backstage/plugin-catalog-backend-module-unprocessed'之类的导入必须改为正确拼写UnprocessedEntitiesModule。当前仓库源码中已统一采用正确拼写,例如 plugins/catalog-backend-module-unprocessed/src/UnprocessedEntitiesModule.ts、module.ts 以及测试文件 UnprocessedEntitiesModule.test.ts。
升级检查清单
对升级到 v1.17.0-next.0 的项目,建议按以下顺序核对:
- 搜索旧拼写:在仓库内全局搜索
UnprocessedEntites,将引用替换为UnprocessedEntities(注意仅此模块有此变更,catalog 本体不受影响); - 验证配置可见性:为新增/存量配置对象补齐
deepVisibility或逐一标注visibility,并运行backstage-cli config:schema(其--merge/--format等选项见 packages/cli/cli-report.md)检查 schema 是否合法; - 回归后端 API:重点验证 catalog/search/todo 的 REST 接口在非法入参下的错误响应是否符合预期,尤其是类型错误的请求是否返回 400
InputError; - 更新依赖:跟随 changelog 中的 Updated dependencies 列表整体升级,确保
backend-openapi-utils等共享包版本一致,避免类型不匹配。
四、其他值得留意的细节变更
除上述三大主题外,本版本还有几处小改动值得记录:
- CLI 体验:
@backstage/cli@0.22.10-next.0在 app 配置变更时会自动重载前端(3f67cefb4780);并支持用--no-merge标志打印未合并的配置 schema(cebbf8a27f3c),便于排查 schema 合并问题; - Home 插件:
plugin-home@0.5.5-next.0的<WelcomeTitle language={['English', 'Spanish']} />支持按语言渲染问候语(a559ff68de7e);AddWidgetDialog在标题为空时回退使用名称(6743d3917a52);plugin-home-react的createCardExtension中title变为可选(bf67dce73174); - Catalog 图:
plugin-catalog-graph@0.2.33-next.0会把 entity 的spec传播到EntityNode,便于基于type等 spec 信息自定义图节点样式(64ee2c0c7ca5); - Analytics 归属修复:
core-app-api修复了导航到非可路由扩展路由时,navigate事件被错误归属到根路由插件(如/下的 home 插件)的问题(9ae4e7e63836); - Linguist 后端:修复了
linguistJsOptions被linguist-js包修改后导致批量任务后续实体失败的问题(ca5e591cb86a); - 新增模块:
plugin-analytics-module-newrelic-browser@0.0.1-next.0引入 New Relic Browser 分析模块(ec7357258853)。
结语
v1.17.0-next.0 是一个"基础设施优先"的预发布版本:deepVisibility让配置可见性声明从"逐字段标注"进化为"对象级递归默认",显著降低敏感配置泄露风险;OpenAPI 请求校验从工具链到三个后端插件全线落地,配合 repo-tools 自动生成类型化 router,把后端 API 的输入契约变成了编译期与运行期的双重保障。建议插件与平台维护者重点关注上述破坏性变更与错误响应变化,利用 next 版本窗口提前完成迁移验证。
延伸阅读:配置可见性相关源码可继续阅读 packages/config-loader/src/schema/compile.ts、packages/config-loader/src/schema/filtering.ts 与 packages/config-loader/src/schema/types.ts;OpenAPI 校验实现见 packages/backend-openapi-utils/src/stub.ts 与 packages/backend-openapi-utils/src/router.ts。
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考