feat(security,rest): getReadableFields query surface for export column projection (#3547) - #3561
Merged
Merged
Conversation
…n projection (#3547) The REST export route projected columns by inferring readability from the first chunk of already-masked data rows (#3498), which drops an all-null readable column and leaves an empty result set un-narrowed. Add the long-term-correct path: a security-service query surface that returns the readable field set for a context, derived from schema + FLS rather than from data rows. - plugin-security: the `security` service gains getReadableFields(object, context). Same evaluator + requiredPermissions fold + on-behalf-of delegator intersection the read middleware's FieldMasker uses (fail-closed on a dangling delegator), returning every schema field NOT masked non-readable — the exact complement of maskResults' delete set, so it can never drift from data-plane FLS. Computed from schema+context, never rows → immune to null/empty results. isSystem bypasses FLS; unresolvable schema → undefined (caller falls back). - rest: GET /data/:object/export asks the environment's security service for getReadableFields and projects the schema-derived header to that set before streaming. No service reachable → degrades to the existing masked-row inference (zero regression). Explicit ?fields= is honored verbatim. Tests: plugin-security getReadableFields (readable=complement of mask, isSystem bypass, no-restriction passthrough, unresolvable→undefined, schema-not-rows); rest export route projects from the service (drops a masked field present in rows; keeps a readable column absent from every row; honors explicit ?fields=). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012L8EfEa157Pe6C73qRnaJH
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 16 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
July 27, 2026 05:49
This was referenced Jul 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
#3391 的独立 follow-up ④(见 #3547)。P1 让 export 的列投影与 list 的字段级权限(FLS)对齐,方案是「从 masked 行推导」:取首块 masked 行的键并集 ∩ schema 字段作为导出表头(
rest-server.tsexport 路由,#3498)。已知两处妥协:本 PR 接入长期正解:给 security 服务加一个
getReadableFields(object, context)查询面,直接返回该 context 下的可读字段集,export 用它做列投影,而不是从数据行反推。改动
security服务新增getReadableFields(object, context)。它解析调用者的 permission sets,并用与读中间件FieldMasker完全相同的 evaluator +requiredPermissionsfold(以及 on-behalf-of 委托者交集,悬空委托者 fail-closed)构建字段权限图,返回未被标记 non-readable 的全部 schema 字段 —— 即maskResults删除集的精确补集,与数据面 FLS 杜绝漂移。由 schema + context 推导,不读数据行,故不受 null 值 / 空结果影响。system context 绕过 FLS;schema 不可解析时返回undefined(调用方回退)。GET /data/:object/export路由在流式输出前向环境的security服务请求getReadableFields(object, context),并据此收窄 schema 派生的表头。无 security 服务可达(无 plugin-security / 单 kernel 无 provider)时回退到既有的「从 masked 行推导」——零回归。显式?fields=仍按请求原样保留。契约 / 兼容
对派生表与前端零契约变更(export ⊆ list,#3391 已定)。本 PR 只是把列投影从「反推」变为「权威查询」。无 spec 改动,无 api-surface / liveness / docs 变更。
测试
get-readable-fields.test.ts):可读集 = 掩码补集;isSystem绕过 FLS 返回全集;无字段规则时全字段直通;schema 不可解析 →undefined;由 schema 而非行推导(空数据仍返回完整可读集)。export-integration.test.tssecurity 服务 getReadableFields 查询面(export 列投影的长期正解) #3547 块):路由从 service 投影列 —— 即便行里仍带该字段也会剔除被掩码字段;某可读列在每一行都缺失时仍保留(null 值免疫);显式?fields=原样保留。关联
🤖 Generated with Claude Code
https://claude.ai/code/session_012L8EfEa157Pe6C73qRnaJH
Generated by Claude Code