fix(analytics): make the read-scope auto-bridge order-independent + first real e2e RLS gate (#3618)#3619
Merged
Merged
Conversation
) `getReadScope` was only wired when the `security` service already existed at this plugin's init(). The closure resolved lazily, but the ASSIGNMENT was gated on an init-time probe — so a kernel registering AnalyticsServicePlugin before the security plugin got no read-scope provider at all, and every analytics strategy ran unscoped behind nothing but a WARN. Both sibling bridges (executeAggregate, executeRawSql) wire unconditionally and resolve at call time, and this one's own comment claimed it did too. Now it does; the probe only picks the log wording. `os serve` registers security first, so the CLI path was already correct. The exposure was embedders composing their own kernel — and this repo's own bootStack harness, which registers analytics at harness.ts:159 and security at :232. That means the entire dogfood/verify suite has been running with analytics RLS silently disabled, so any analytics RLS assertion written there passed vacuously. Also corrects the WARN text: with no provider nothing is scoped on any path or object, not just "the raw-SQL path" / "joined objects". Adds analytics-rls.dogfood.test.ts — an owner-scoped RLS fixture driven over real HTTP as a real non-admin, asserting the rows a member's aggregate actually returns rather than inspecting a filter object. This is the first test to exercise the getReadScope -> security.getReadFilter auto-bridge at all. Found while writing the end-to-end gate for #3597: the gate went red for THIS reason, not that one. Reverting this fix turns 3 of its 4 cases red; reverting the #3597 strategy fix turns the ObjectQL case red. Co-Authored-By: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 8 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
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.
Closes #3618. 端到端补上 #3597 我明确说过没做的那一环。
起因:门先红了,但不是为 #3597 红的
给 #3597 写真实栈端到端门时,member 的聚合在两条 strategy 上都返回全表 5 行 —— 连 #3601 刚修好的 NativeSQL 路径也漏。前提检查是过的(
GET /data/rls_note只返回 member 自己的 2 条),说明 owner 策略在普通读路径上生效。日志给出了答案:
另外两个桥都接上了,只有 read-scope 桥没接。
缺陷:代码和它自己的注释矛盾
plugin.ts:277-306注释写着 "resolved at call time so plugin-init order does not matter",但:闭包是懒的,可赋值本身被 init 时刻的探测卡住了。security 晚注册 ⇒
getReadScope恒undefined⇒callCtx在analytics-service.ts:332直接return this.baseCtx⇒ 两条 strategy 都不加 scope。两个兄弟桥都是对的,只有它不是 ——
executeRawSql的注释甚至明写 "Always wire the bridge... plugin-init order does not matter"。影响面(诚实划界)
生产 CLI 不受影响:
os serve里 SecurityPlugin 在serve.ts:1658,analytics 由 capability resolver 在其之后加载,顺序正确。受影响的是:
bootStack—— analytics 在harness.ts:159,security 在:232。整个 dogfood/verify 套件的 analytics RLS 一直是关的,那里写的任何 analytics RLS 断言都是空过的。修复
getReadScope无条件接线,探测只用来决定日志措辞 —— 与两个兄弟桥一致。顺带改掉 WARN 的错误措辞(原文说只影响 "raw-SQL path" 的 "joined objects";实际没 provider 时所有路径所有对象都不加 scope)。新增的门
packages/qa/dogfood/test/analytics-rls.dogfood.test.ts—— 第一个真正跑通getReadScope → security.getReadFilter自动桥的测试。此前所有 analytics RLS 测试都是往手搓的AnalyticsService注入假getReadScope,所以这条桥零覆盖,这也正是缺陷能活下来的原因。断言的是真实非管理员经 HTTP 拿到的行,不是某个 filter 对象:
dateGranularity,NativeSQL 会声明失败)→ member 只数到自己的 2 行用 owner-scoped(
created_by)而非 org-scoped 是刻意的:没有企业版org-scoping服务时,wildcardorganization_id策略会被剥掉,门会静默常绿。owner 策略引用current_user.id,单租户 boot 下依然生效。验证
plugin.ts改动 → 红 3 个;回退 fix(analytics): enforce read scope on the ObjectQL aggregate path (#3597) #3601 的 strategy 改动 → ObjectQL 那条红。@objectstack/service-analytics179 passed。tsc --noEmit未引入新错误(该包 2 个存量错误在我没碰的测试文件里)。待核
cloud是独立仓库,我没检查它的插件注册顺序。若任何已发布 composition 用了不利顺序,#3618 应升级到 p1。🤖 Generated with Claude Code