Backstage v1.36.0-next.0 深度解读:auditor 审计服务、PermissionsRegistry 与原生 ESM 支持
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
本篇技术解读以 docs/releases/v1.36.0-next.0-changelog.md 为骨架,围绕 Backstage 1.36.0 首个预发布版本(next.0)的核心变更展开:全新的auditor核心服务与PermissionsRegistryService如何重塑后端插件的能力边界,CLI 原生 ESM 支持带来的破坏性变更应如何迁移,以及 Canon、TechDocs 自定义首页等前端增强的实战用法。读完本文,你将掌握本版本中每个破坏性变更的迁移要点,并能直接落地 auditor 事件埋点与权限规则注册的完整代码。
版本总览:一次面向新后端系统的能力升级
v1.36.0-next.0 是一轮覆盖后端服务、CLI 工具链与前端组件体系的预发布迭代,其中几个关键包的版本变化直接决定了升级工作的规模:
| 包 | 新版本 | 变更级别 | 核心内容 |
|---|---|---|---|
| @backstage/backend-plugin-api | 1.2.0-next.0 | Minor | 新增auditor服务定义与PermissionsRegistryService |
| @backstage/backend-defaults | 0.8.0-next.0 | Minor | 提供auditor服务的默认实现 |
| @backstage/backend-test-utils | 1.3.0-next.0 | Minor | 为两个新服务提供测试 mock |
| @backstage/cli | 0.30.0-next.0 | BREAKING | Node.js 代码原生 ESM 支持 |
| @backstage/canon | 0.1.0-next.0 | 首个 alpha | Canon 组件库首次发布 |
| @backstage/plugin-catalog-backend | 1.31.0-next.0 | Minor | 接入PermissionsRegistryService与auditor |
| @backstage/plugin-scaffolder-backend | 1.30.0-next.0 | Minor | 接入auditor服务 |
| @backstage/plugin-techdocs-node | 1.13.0-next.0 | Minor | AWS S3 发布器支持可配置重试 |
此外,@backstage/plugin-catalog-node@1.15.2-next.0正式弃用了 alpha 状态的catalogPermissionExtensionPoint及相关类型,其功能已由新的PermissionsRegistryService完全取代。
auditor 服务:为后端插件引入统一审计能力
本版本最核心的架构级变更,是在 packages/backend-plugin-api/src/services/definitions/AuditorService.ts 中新增的AuditorService接口,并通过coreServices.auditor(id 为core.auditor,见 coreServices.ts)暴露给所有后端插件。
服务接口与事件模型
从源码定义看,AuditorService只暴露一个方法:
export interface AuditorService { createEvent( options: AuditorServiceCreateEventOptions, ): Promise<AuditorServiceEvent>; }createEvent接收的事件选项包含四个字段:
- eventId(必填):采用 kebab-case 命名(如
user-login、file-download、fetch),表示一组相似事件或操作的逻辑聚合。例如fetch可作为事件 ID,涵盖by-id、by-location等多种具体取数方式。由于pluginId已提供插件/模块上下文,eventId中应避免冗余的前缀。 - severityLevel(可选):事件严重级别,取值与含义在源码注释中明确给出:
low(默认):常规使用medium:访问写端点high:非 root 权限变更critical:root 权限变更
- request(可选):关联的 HTTP 请求对象(express
Request)。 - meta(可选):附加元数据,结构化 JSON 对象。其中可含
queryType字段(同样使用 kebab-case),用于表达主事件内的变体,例如eventId为fetch时,meta.queryType可为by-id或by-location。
createEvent返回一个AuditorServiceEvent,它提供了显式的成功/失败回调:
export type AuditorServiceEvent = { success(options?: { meta?: JsonObject }): Promise<void>; fail(options: { meta?: JsonObject; error: Error }): Promise<void>; };这种"先创建、后标记成败"的模型,让插件可以在操作的整个生命周期内携带审计上下文,最终以成功或失败两种状态落盘。
默认实现与日志输出
默认实现位于 packages/backend-defaults/src/entrypoints/auditor/auditorServiceFactory.ts。从源码可以确认其依赖与行为:
- 服务工厂依赖
rootConfig、logger、auth、httpAuth与pluginMetadata五个核心服务; - 它基于
logger.child({ isAuditEvent: true })派生专用审计日志器,审计事件会统一打上isAuditEvent: true标记,便于日志采集系统区分; - 日志记录键为
`${event.plugin}.${event.eventId}`,即插件 ID 与事件 ID 拼接; - 事件失败时(
'error' in event),错误对象会被单独作为第二个参数传给日志方法; - 严重级别到日志级别的映射由
getSeverityLogLevelMappings(config)从配置中解析,意味着审计日志的落盘级别可随配置调整。
插件集成现状
从变更日志看,auditor服务已在本版本中完成首批落地:
- plugins/catalog-backend:Catalog 插件接入
auditor服务(变更 a4aa244); - plugins/scaffolder-backend:Scaffolder 插件接入
auditor服务(变更 a4aa244)。
对于插件开发者,接入审计服务的方式是在插件或模块中通过依赖注入获取coreServices.auditor,例如:
import { coreServices, createBackendModule } from '@backstage/backend-plugin-api'; createBackendModule({ pluginId: 'my-plugin', moduleId: 'audit-demo', register(env) { env.registerInit({ deps: { auditor: coreServices.auditor }, async init({ auditor }) { const event = await auditor.createEvent({ eventId: 'fetch', severityLevel: 'low', meta: { queryType: 'by-id' }, }); try { // 执行业务操作... await event.success(); } catch (error) { await event.fail({ error }); } }, }); }, });测试支撑
packages/backend-test-utils 为auditor服务提供了现成的 mock(变更 a4aa244),相关单元测试(如DefaultAuditorService.test.ts、WinstonRootAuditorService.test.ts、auditorServiceFactory.test.ts,均位于 packages/backend-defaults/src/entrypoints/auditor)也随实现一同落地,可在测试中直接验证事件的成功/失败路径。
PermissionsRegistryService:权限注册的新标准入口
第二个关键架构变更是PermissionsRegistryService,其接口定义在 packages/backend-plugin-api/src/services/definitions/PermissionsRegistryService.ts,通过coreServices.permissionsRegistry(id 为core.permissionsRegistry)暴露。它取代了原先通过createPermissionIntegrationRouter(来自@backstage/plugin-permission-node)注册权限的模式。
四个核心方法
从源码看,该服务提供四个方法:
addPermissions(permissions: Permission[]):为插件向权限系统注册权限。addPermissionRules(rules: PermissionRule<any, any, string>[]):为插件拥有的资源类型注册一组权限规则。规则应使用各插件导出的create*PermissionRule函数创建(这些函数本身由makeCreatePermissionRule派生),插件自身或其模块均可添加规则。addResourceType(options):注册一个新的资源类型,其选项包括:resourceRef:标识资源类型的PermissionResourceRef;permissions:该资源类型可用的权限列表;rules:该资源类型可用的权限规则数组,描述如何过滤资源列表(如 Catalog 的isEntityOwner、hasAnnotation),并支持以特定参数构造条件;getResources:根据引用标识符加载关联资源的函数。若未提供,权限系统将无法解析条件化授权决策(除非直接从插件请求资源)。
getPermissionRuleset(resourceRef):返回已注册的规则集,主要用于配合createConditionAuthorizer与createConditionTransformer使用。
源码注释以 Catalog 为例说明了addResourceType的语义:Catalog 围绕对具体实体的访问有条件规则,resourceType是像catalog-entity这样的字符串标识,它只是用于校验授权策略中条件构造正确性的"类型",而非对具体资源的引用。
集成与弃用
- plugins/catalog-backend 已支持通过新的
PermissionsRegistryService添加自定义权限规则(变更 8805f93); - plugins/catalog-backend-module-unprocessed 改用新服务替代已弃用的
catalogPermissionExtensionPoint(变更 4e073c7); - plugins/catalog-node 弃用了 alpha 状态的
catalogPermissionExtensionPoint及相关类型(变更 4a941e7); - 默认实现与工厂测试位于 packages/backend-defaults/src/entrypoints/permissionsRegistry;
- 配套地,
@backstage/plugin-permission-node@0.8.8-next.0中createPermissionIntegrationRouter返回的路由器变为可变对象,允许在创建之后继续添加权限与资源(变更 049d5d4),为过渡期提供兼容空间。
@backstage/backend-test-utils同样为本服务提供了 mock(变更 dd05a97)。
破坏性变更:CLI 原生 ESM 支持
@backstage/cli@0.30.0-next.0引入了 Node.js 代码的原生 ESM 支持(变更 cb76663),这是本轮升级中最需要关注的手工迁移点。
行为变化
原生 ESM 支持改变了 Node.js 代码中动态导入表达式的行为:动态import(...)将不再被转译为require(...),而是原样保留。这带来的能力提升包括:
- 允许从 CommonJS 代码中通过动态导入加载 ESM 模块;
.mjs/.mts作为显式 ESM 文件,.cjs/.cts作为显式 CommonJS 文件;- 支持在
package.json中声明"type": "module"将包标记为 ESM 包。
上述能力在类型检查、包构建、运行时转换与 Jest 测试中全部生效。
迁移要点
对于大多数插件/应用代码,修复方式是把import(...)替换为require(...),需要类型时再配合as typeof import(...)断言:
// 之前(会被转译为 require) const mod = await import('./some-module'); // 之后(原生动态导入) const mod = require('./some-module') as typeof import('./some-module');四个重要注意事项
根据变更日志,以下 caveat 需要特别注意:
- 测试启用原生 ESM 需要
--experimental-vm-modules:通常在运行测试时通过NODE_OPTIONS='--experimental-vm-modules'注入。 "type": "module"的传染效应:在package.json中声明"type": "module"是受支持的,但在测试环境中,它会将所有本地传递依赖也视为 ESM——无论这些依赖自身是否声明了"type": "module"。- ESM 互操作层的启用条件:Node.js 的 ESM/CommonJS 互操作层仅在导入带
.cts或.cjs扩展名的包时启用。原因是该互操作层与 NPM 生态并不完全兼容,若对.js文件启用会破坏包。 - 避免动态导入 CommonJS 包:动态导入 CommonJS 包的结果形状会随运行环境(测试 vs 本地开发等)变化。因此建议改用
require,或使用上述显式 CommonJS 扩展名;如果确实需要动态导入 CommonJS 包,应避免使用default导出,因为其形状在不同环境间不一致,否则需要根据模块对象的形状手动解包。
此外,@backstage/cli-node@0.2.13-next.0同步在BackstagePackageJson类型中增加了type字段,@backstage/config-loader、@backstage/backend-defaults等包也进行了显式require的懒加载重构(变更 f866b86)。
Canon:全新组件库的首个 alpha
@backstage/canon@0.1.0-next.0是 Canon 的首次 alpha 发布(变更 65f4acc),本次引入:
- 5 个布局(layout)组件;
- 7 个通用组件;
- 所有主题化均通过CSS 变量完成。
这意味着开发者可以在不引入 Material UI 主题上下文的前提下,通过 CSS 变量对 Canon 组件进行风格定制,适合对样式控制粒度有更高要求的场景。
TechDocs 自定义首页能力增强
plugins/techdocs 在本次迭代中大幅增强了文档首页的自定义能力(变更 1f40e6b):
TechDocsCustomHome 新增可选 props
TechDocsCustomHome现在支持通过tabsConfig配置多标签页的文档聚合页,并通过filter精确筛选实体。一个完整的配置示例(来自变更日志):
import { TechDocsCustomHome } from '@backstage/plugin-techdocs'; //... const options = { emptyRowsWhenPaging: false }; const linkDestination = (entity: Entity): string | undefined => { return entity.metadata.annotations?.['external-docs']; }; const techDocsTabsConfig = [ { label: 'Recommended Documentation', panels: [ { title: 'Golden Path', description: 'Documentation about standards to follow', panelType: 'DocsCardGrid', panelProps: { CustomHeader: () => <ContentHeader title='Golden Path'/> }, filterPredicate: entity => entity?.metadata?.tags?.includes('golden-path') ?? false, }, { title: 'Recommended', description: 'Useful documentation', panelType: 'InfoCardGrid', panelProps: { CustomHeader: () => <ContentHeader title='Recommended' /> linkDestination: linkDestination, }, filterPredicate: entity => entity?.metadata?.tags?.includes('recommended') ?? false, }, ], }, { label: 'Browse All', panels: [ { description: 'Browse all docs', filterPredicate: filterEntity, panelType: 'TechDocsIndexPage', title: 'All', panelProps: { PageWrapper: React.Fragment, CustomHeader: React.Fragment, options: options }, }, ], }, ]; const AppRoutes = () => { <FlatRoutes> <Route path="/docs" element={ <TechDocsCustomHome tabsConfig={techDocsTabsConfig} filter={{ kind: ['Location', 'Resource', 'Component'], 'metadata.annotations.featured-docs': CATALOG_FILTER_EXISTS, }} CustomPageWrapper={({ children }: React.PropsWithChildren<{}>) => (<PageWithHeader title="Docs" themeId="documentation">{children}</PageWithHeader>)} /> } /> </FlatRoutes>; };新增 InfoCardGrid 与独立 CustomDocsPanel
- 新增网格选项
InfoCardGrid:更可定制的文档卡片网格,支持自定义linkContent与linkDestination:
<InfoCardGrid entities={entities} linkContent="Learn more" linkDestination={entity => entity.metadata['external-docs']} />- 原有的
CustomDocsPanel被导出,可独立使用。借助PanelConfig数组,开发者可以灵活拼装不同 panel 类型:
const panels: PanelConfig[] = [ { description: '', filterPredicate: entity => {}, panelType: 'InfoCardGrid', title: 'Standards', panelProps: { CustomHeader: () => <ContentHeader title='Recommended' /> linkDestination: linkDestination, }, }, { description: '', filterPredicate: entity => {}, panelType: 'DocsCardGrid', title: 'Contribute', }, ]; { panels.map((config, index) => ( <CustomDocsPanel key={index} config={config} entities={!!entities ? entities : []} index={index} /> )); }其他 TechDocs 修复
addLinkClickListener的基础 URL 从window.location.origin改为app.baseUrl(变更 f4be934),修复了 Backstage 运行在子路径(subpath)时无法正确处理同源非 Backstage URL 的问题;- plugins/techdocs-node 与
@techdocs/cli@1.9.0-next.0支持为 AWS S3 发布操作配置可选重试(变更 8de3d2d)。
其余值得关注的变更
本轮还包含一系列影响面较小但值得留意的更新:
- Scaffolder 任务上下文新增
taskId:plugins/scaffolder-node 的TaskContext增加可选taskId属性(变更 a4aa244),相关类型定义可见 plugins/scaffolder-node/src/alpha/index.ts,为任务级操作(如按taskId清理工作区)提供依据。 - 通知系统主题过滤:
@backstage/plugin-notifications与@backstage/plugin-notifications-backend新增 topic 过滤器(变更 438c36c)。 - 搜索过滤扩展点:
@backstage/plugin-search与@backstage/plugin-search-react新增SearchFilterBlueprint与SearchFilterResultTypeBlueprint,可扩展搜索过滤与结果类型(变更 63e1012)。 - Kubernetes 额外对象抓取:
@backstage/plugin-kubernetes-backend支持指定默认对象之外的其他 Kubernetes 对象,以补充secrets等资源的获取(变更 ac0e1ac)。 - Catalog 稳定性修复:
- stitching 期间良性数据库冲突错误降级为 debug 级日志(变更 c9139e1);
- 清理不再控制某
refresh_state行的 processor/provider 对应的refresh_state_references(变更 f178b12); - 搜索索引的 location URL 生成改用
encodeURIComponent编码实体属性值,提升 URL 安全性与可靠性(变更 eee8d76)。
- 前端应用树 API:
frontend-app-api与frontend-plugin-api的AppTreeApi新增getNodesByRoutePath方法(变更 3e21b8d)。 - Scaffolder 组件修复:修复
BitbucketRepoBranchPicker导致页面崩溃的问题(变更 3107f1f);makeFieldSchema返回值新增 schema 输出返回类型(变更 3edf7e7)。 - repo-tools:
api-reports命令新增--sql-reports标志,可生成 SQL 报告(变更 98ddf05)。 - 后端动态特性服务:packages/backend-dynamic-feature-service 确保变更被成功跟踪后再启动扫描器(变更 96c20cd)。
升级路径建议
基于以上变更,从 v1.35.x 升级到 v1.36.0 正式版前,建议按以下顺序自查:
- 优先处理 CLI ESM 迁移:全局搜索仓库中的动态
import(...)调用,评估是否涉及 ESM 模块加载;按照"用require替代 +as typeof import保类型"的模式逐一替换;若测试需要原生 ESM,为 Jest 配置NODE_OPTIONS='--experimental-vm-modules',并注意"type": "module"在测试中的传递性影响。 - 评估权限注册迁移:若插件使用了
catalogPermissionExtensionPoint,迁移到coreServices.permissionsRegistry;若使用了createPermissionIntegrationRouter,注意其返回路由器已变为可变对象,可按需渐进迁移。 - 关注服务版本对齐:
backend-plugin-api、backend-defaults、backend-test-utils三个包必须同步升级到 1.2.0 / 0.8.0 / 1.3.0 的 next 版本线,否则新服务引用无法解析。 - 验证 TechDocs 行为变化:若运行在子路径部署,升级后验证文档内链接跳转行为符合预期。
完整变更条目可随时查阅仓库内的 docs/releases/v1.36.0-next.0-changelog.md;升级前建议结合 docs/releases/v1.35.0-changelog.md 确认上一版本的已知问题。
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考