Skip to content

feat(security,rest): getReadableFields query surface for export column projection (#3547) - #3561

Merged
os-zhuang merged 1 commit into
mainfrom
claude/complete-scheduled-development-xqcwch
Jul 27, 2026
Merged

feat(security,rest): getReadableFields query surface for export column projection (#3547)#3561
os-zhuang merged 1 commit into
mainfrom
claude/complete-scheduled-development-xqcwch

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

背景

#3391 的独立 follow-up ④(见 #3547)。P1 让 export 的列投影与 list 的字段级权限(FLS)对齐,方案是「从 masked 行推导」:取首块 masked 行的键并集 ∩ schema 字段作为导出表头(rest-server.ts export 路由,#3498)。已知两处妥协:

  • 首块行里某可读字段若恰好全为 null(且驱动省略 null 键),该列表头会消失(纯外观问题)。
  • 空结果集时没有行可供收窄。

本 PR 接入长期正解:给 security 服务加一个 getReadableFields(object, context) 查询面,直接返回该 context 下的可读字段集,export 用它做列投影,而不是从数据行反推。

改动

  • plugin-security —— security 服务新增 getReadableFields(object, context)。它解析调用者的 permission sets,并用与读中间件 FieldMasker完全相同的 evaluator + requiredPermissions fold(以及 on-behalf-of 委托者交集,悬空委托者 fail-closed)构建字段权限图,返回未被标记 non-readable 的全部 schema 字段 —— 即 maskResults 删除集的精确补集,与数据面 FLS 杜绝漂移。由 schema + context 推导,不读数据行,故不受 null 值 / 空结果影响。system context 绕过 FLS;schema 不可解析时返回 undefined(调用方回退)。
  • rest —— 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 变更。

测试

  • plugin-security(get-readable-fields.test.ts):可读集 = 掩码补集;isSystem 绕过 FLS 返回全集;无字段规则时全字段直通;schema 不可解析 → undefined;由 schema 而非行推导(空数据仍返回完整可读集)。
  • rest(export-integration.test.tssecurity 服务 getReadableFields 查询面(export 列投影的长期正解) #3547 块):路由从 service 投影列 —— 即便行里仍带该字段也会剔除被掩码字段;某可读列在每一行都缺失时仍保留(null 值免疫);显式 ?fields= 原样保留。
  • 全量:plugin-security 547 / rest 377 通过;plugin-security + rest 构建(CJS/ESM/DTS)全绿。

关联

🤖 Generated with Claude Code

https://claude.ai/code/session_012L8EfEa157Pe6C73qRnaJH


Generated by Claude Code

…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
@vercel

vercelBot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
objectstackReadyReadyPreview, CommentJul 27, 2026 5:47am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/plugin-security, @objectstack/rest.

16 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/api/error-catalog.mdx(via @objectstack/rest)
  • content/docs/api/error-handling-server.mdx(via @objectstack/rest)
  • content/docs/api/index.mdx(via @objectstack/rest)
  • content/docs/deployment/cli.mdx(via @objectstack/plugin-security)
  • content/docs/permissions/access-recipes.mdx(via packages/plugins/plugin-security)
  • content/docs/permissions/authorization.mdx(via @objectstack/plugin-security)
  • content/docs/permissions/explain.mdx(via @objectstack/plugin-security)
  • content/docs/permissions/permissions-matrix.mdx(via packages/plugins/plugin-security)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/plugin-security)
  • content/docs/plugins/index.mdx(via @objectstack/plugin-security, @objectstack/rest)
  • content/docs/plugins/packages.mdx(via @objectstack/plugin-security, @objectstack/rest)
  • content/docs/protocol/kernel/i18n-standard.mdx(via packages/rest)
  • content/docs/releases/implementation-status.mdx(via @objectstack/plugin-security, @objectstack/rest)
  • content/docs/releases/v12.mdx(via @objectstack/rest)
  • content/docs/ui/audience-based-interfaces.mdx(via packages/plugins/plugin-security)
  • content/docs/ui/dashboards.mdx(via @objectstack/plugin-security)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@os-zhuang@claude