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.ts security 服务 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

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
objectstack Ready Ready Preview, Comment Jul 27, 2026 5:47am

Request Review

@github-actions github-actions Bot 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 free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants