news 2026/9/12 18:06:44

Backstage v1.17.0-next.0 版本速览:deepVisibility 配置可见性、OpenAPI 请求校验与破坏性变更解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Backstage v1.17.0-next.0 版本速览:deepVisibility 配置可见性、OpenAPI 请求校验与破坏性变更解析

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-loader1.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)

  1. 通过 AJV 注册deepVisibility关键字,其metaSchema的枚举被刻意限制为['frontend', 'secret']——不允许backend。源码注释解释了原因:禁止backend深度可见性,是为了防止"权限逃逸"(permission escaping),即避免出现deepVisibility secret -> backend -> frontenddeepVisibility secret -> backend -> visibility frontend这类逐级降级再重新暴露的链条(见 compile.ts);
  2. 校验时,把每个设置了deepVisibility的数据路径记录进deepVisibilityByDataPath映射表;
  3. 遍历合并后的 schema 时,子节点若未显式声明,则继承父节点的deepVisibilityschema[inheritedVisibility] ??= schema?.deepVisibility ?? parentSchema?.[inheritedVisibility],见 compile.ts);
  4. 对同一路径下同时出现frontendsecret冲突的情况直接抛错: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'时,未标注的子节点(ac、数组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 披露了两件事:

  1. 新增createRouter方法,用于生成一个基于你的 OpenAPI spec 进行请求校验的 express router
  2. 修复了查询参数类型解析的一个 bug。

从 packages/backend-openapi-utils/src/stub.ts 的实现可以看到,createRouterWithValidation的核心机制:

  • 基于express-promise-router创建 router;
  • 挂载express-openapi-validator中间件,默认配置为validateRequests.coerceTypes: false(不隐式做类型转换,所以"a"不会被强转成数字,而是校验失败)、allowUnknownQueryParameters: falsevalidateResponses: false
  • 任何来自校验中间件的错误都会被转换为@backstage/errors中的InputError(见 stub.ts);
  • 同时暴露OPENAPI_SPEC_ROUTE路由,通过openapi-merge把当前 spec 以 JSON 形式提供出去,便于开发者直接在运行时查看该插件的 OpenAPI 文档。

对外公开的两个工厂函数createValidatedOpenApiRoutercreateValidatedOpenApiRouterFromGeneratedEndpointMap分别返回基于文档类型或生成端点映射的类型化 routerApiRouter/TypedRouter)。TypedRouter在 router.ts 中定义,为get/post/put/delete提供了按 EndpointMap 推导的请求/响应类型——这意味着调用方在编译期就能得到入参与返回值的类型检查。

2.2 生成物:repo-tools 的 schema openapi generate 升级

配套地,@backstage/repo-tools@0.3.3-next.0schema 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 的项目,建议按以下顺序核对:

  1. 搜索旧拼写:在仓库内全局搜索UnprocessedEntites,将引用替换为UnprocessedEntities(注意仅此模块有此变更,catalog 本体不受影响);
  2. 验证配置可见性:为新增/存量配置对象补齐deepVisibility或逐一标注visibility,并运行backstage-cli config:schema(其--merge/--format等选项见 packages/cli/cli-report.md)检查 schema 是否合法;
  3. 回归后端 API:重点验证 catalog/search/todo 的 REST 接口在非法入参下的错误响应是否符合预期,尤其是类型错误的请求是否返回 400InputError
  4. 更新依赖:跟随 changelog 中的 Updated dependencies 列表整体升级,确保backend-openapi-utils等共享包版本一致,避免类型不匹配。

四、其他值得留意的细节变更

除上述三大主题外,本版本还有几处小改动值得记录:

  • CLI 体验@backstage/cli@0.22.10-next.0在 app 配置变更时会自动重载前端(3f67cefb4780);并支持用--no-merge标志打印未合并的配置 schemacebbf8a27f3c),便于排查 schema 合并问题;
  • Home 插件plugin-home@0.5.5-next.0<WelcomeTitle language={['English', 'Spanish']} />支持按语言渲染问候语(a559ff68de7e);AddWidgetDialog在标题为空时回退使用名称(6743d3917a52);plugin-home-reactcreateCardExtensiontitle变为可选(bf67dce73174);
  • Catalog 图plugin-catalog-graph@0.2.33-next.0会把 entity 的spec传播到EntityNode,便于基于type等 spec 信息自定义图节点样式(64ee2c0c7ca5);
  • Analytics 归属修复core-app-api修复了导航到非可路由扩展路由时,navigate事件被错误归属到根路由插件(如/下的 home 插件)的问题(9ae4e7e63836);
  • Linguist 后端:修复了linguistJsOptionslinguist-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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 18:06:15

LLM与Agent技术融合:从原理到多智能体协作实践

1. 项目概述&#xff1a;LLM与Agent技术全景解析 在人工智能领域&#xff0c;大语言模型&#xff08;LLM&#xff09;与智能体&#xff08;Agent&#xff09;技术的结合正掀起新一轮变革浪潮。这组技术组合不仅重塑了人机交互方式&#xff0c;更在自动化流程、知识管理等领域展…

作者头像 李华
网站建设 2026/9/12 18:05:41

Cataclysm-DDA 建造系统新手指南:从第一面木墙到末日庇护所

Cataclysm-DDA 建造系统新手指南&#xff1a;从第一面木墙到末日庇护所 【免费下载链接】Cataclysm-DDA Cataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world. 项目地址: https://gitcode.com/GitHub_Trending/ca/Cataclysm-DDA …

作者头像 李华
网站建设 2026/9/12 18:05:34

牡丹芍药春季养护:抹芽疏蕾技巧与时机把握

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 18:05:02

Flutter鸿蒙系统设置适配方案与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 18:03:51

Spring AI Alibaba框架:Java智能体开发实战指南

1. Spring AI Alibaba框架概述Spring AI Alibaba是阿里云基于Spring AI生态构建的Java智能体开发框架&#xff0c;它深度整合了通义系列大模型能力与云原生基础设施。作为企业级AI应用开发解决方案&#xff0c;该框架显著降低了Java开发者构建智能体应用的技术门槛。我在实际项…

作者头像 李华
网站建设 2026/9/12 18:03:44

32.768kHz晶振原理与低功耗RTC设计实战指南

1. 为什么一块电子表的“心跳”必须是32768赫兹&#xff1f;你拆开过一块老式石英电子表吗&#xff1f;翻开后盖&#xff0c;那颗米粒大小、银光闪闪的圆柱形小金属壳&#xff0c;就是它的“心脏”——32.768kHz晶振。它不发声&#xff0c;却每秒精准振动32768次&#xff1b;它…

作者头像 李华